This is an automated email from the ASF dual-hosted git repository. pauls pushed a commit to branch SLING-8411 in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-jcr-base.git
commit 63e79550819e48d436b53903862d68253a501e40 Author: Karl Pauls <[email protected]> AuthorDate: Thu May 9 16:55:12 2019 +0200 SLING-8411: Provide a way to bifurcat a repository path to a provider mount. --- pom.xml | 8 +- .../sling/jcr/base/AbstractSlingRepository2.java | 27 +- .../jcr/base/AbstractSlingRepositoryManager.java | 44 +- .../jcr/base/internal/mount/ChainedIterator.java | 75 +++ .../internal/mount/ProxyAccessControlManager.java | 107 ++++ .../sling/jcr/base/internal/mount/ProxyItem.java | 135 +++++ .../mount/ProxyJackrabbitAccessControlManager.java | 77 +++ .../internal/mount/ProxyJackrabbitRepository.java | 59 ++ .../internal/mount/ProxyJackrabbitSession.java | 85 +++ .../internal/mount/ProxyJackrabbitWorkspace.java | 42 ++ .../sling/jcr/base/internal/mount/ProxyLock.java | 75 +++ .../internal/mount/ProxyNamespaceRegistry.java | 67 +++ .../sling/jcr/base/internal/mount/ProxyNode.java | 413 ++++++++++++++ .../base/internal/mount/ProxyNodeTypeManager.java | 111 ++++ .../base/internal/mount/ProxyPrivilegeManager.java | 62 +++ .../jcr/base/internal/mount/ProxyProperty.java | 157 ++++++ .../sling/jcr/base/internal/mount/ProxyQuery.java | 233 ++++++++ .../jcr/base/internal/mount/ProxyQueryManager.java | 55 ++ .../base/internal/mount/ProxyQueryObjectModel.java | 47 ++ .../mount/ProxyQueryObjectModelFactory.java | 183 ++++++ .../jcr/base/internal/mount/ProxyQueryResult.java | 46 ++ .../jcr/base/internal/mount/ProxyRepository.java | 133 +++++ .../jcr/base/internal/mount/ProxySession.java | 615 +++++++++++++++++++++ .../jcr/base/internal/mount/ProxyUserManager.java | 123 +++++ .../jcr/base/internal/mount/ProxyWorkspace.java | 168 ++++++ .../jcr/base/internal/mount/ProxyWrapper.java | 40 ++ .../apache/sling/jcr/base/spi/RepositoryMount.java | 27 + .../apache/sling/jcr/base/spi/package-info.java | 27 + 28 files changed, 3231 insertions(+), 10 deletions(-) diff --git a/pom.xml b/pom.xml index 453b538..bab9c73 100644 --- a/pom.xml +++ b/pom.xml @@ -116,7 +116,7 @@ <dependency> <groupId>org.apache.jackrabbit</groupId> <artifactId>jackrabbit-api</artifactId> - <version>2.0.0</version> + <version>2.13.4</version> <scope>provided</scope> </dependency> <dependency> @@ -131,6 +131,12 @@ <version>1.3.6</version> <scope>provided</scope> </dependency> + <dependency> + <groupId>org.apache.jackrabbit</groupId> + <artifactId>oak-commons</artifactId> + <version>1.8.2</version> + <scope>provided</scope> + </dependency> <!-- OSGi Libraries --> <dependency> diff --git a/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepository2.java b/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepository2.java index d6d7307..56cbf81 100644 --- a/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepository2.java +++ b/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepository2.java @@ -36,6 +36,7 @@ import javax.jcr.Value; import javax.security.auth.Subject; import org.apache.sling.jcr.api.SlingRepository; +import org.apache.sling.jcr.base.internal.mount.ProxyRepository; import org.apache.sling.serviceusermapping.ServiceUserMapper; import org.osgi.annotation.versioning.ProviderType; import org.osgi.framework.Bundle; @@ -159,14 +160,22 @@ public abstract class AbstractSlingRepository2 implements SlingRepository { private Session createServiceSession(Bundle usingBundle, String subServiceName, String workspaceName) throws RepositoryException { final ServiceUserMapper serviceUserMapper = this.getSlingRepositoryManager().getServiceUserMapper(); if (serviceUserMapper != null) { + Session session = null; final Iterable<String> principalNames = serviceUserMapper.getServicePrincipalNames(usingBundle, subServiceName); if (principalNames != null) { - return createServiceSession(principalNames, workspaceName); + session = createServiceSession(principalNames, workspaceName); } - - final String userName = serviceUserMapper.getServiceUserID(usingBundle, subServiceName); - if (userName != null) { - return createServiceSession(userName, workspaceName); + else + { + final String userName = serviceUserMapper.getServiceUserID(usingBundle, subServiceName); + if (userName != null) + { + session = createServiceSession(userName, workspaceName); + } + } + if (session != null) { + Repository repository = getRepository(); + return repository instanceof ProxyRepository ? ((ProxyRepository) repository).wrap(session) : session; } } return null; @@ -196,7 +205,9 @@ public abstract class AbstractSlingRepository2 implements SlingRepository { Session admin = null; try { admin = this.createAdministrativeSession(workspace); - return admin.impersonate(new SimpleCredentials(serviceUserName, new char[0])); + Session result = admin.impersonate(new SimpleCredentials(serviceUserName, new char[0])); + Repository repository = getRepository(); + return repository instanceof ProxyRepository ? ((ProxyRepository) repository).wrap(result) : result; } finally { if (admin != null) { admin.logout(); @@ -445,7 +456,9 @@ public abstract class AbstractSlingRepository2 implements SlingRepository { } logger.debug("SlingRepository.loginAdministrative is deprecated. Please use SlingRepository.loginService."); - return createAdministrativeSession(workspace); + Session result = createAdministrativeSession(workspace); + Repository repository = getRepository(); + return repository instanceof ProxyRepository ? ((ProxyRepository) repository).wrap(result) : result; } // Remaining Repository service methods all backed by the actual diff --git a/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepositoryManager.java b/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepositoryManager.java index 761c956..8e54c49 100644 --- a/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepositoryManager.java +++ b/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepositoryManager.java @@ -21,20 +21,27 @@ package org.apache.sling.jcr.base; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Dictionary; +import java.util.HashSet; +import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import javax.jcr.Repository; +import org.apache.jackrabbit.api.JackrabbitRepository; import org.apache.sling.jcr.api.SlingRepository; import org.apache.sling.jcr.api.SlingRepositoryInitializer; import org.apache.sling.jcr.base.internal.loader.Loader; import org.apache.sling.jcr.base.internal.LoginAdminWhitelist; +import org.apache.sling.jcr.base.internal.mount.ProxyJackrabbitRepository; +import org.apache.sling.jcr.base.internal.mount.ProxyRepository; +import org.apache.sling.jcr.base.spi.RepositoryMount; import org.apache.sling.serviceusermapping.ServiceUserMapper; import org.osgi.annotation.versioning.ProviderType; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; +import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceFactory; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; @@ -116,6 +123,8 @@ public abstract class AbstractSlingRepositoryManager { private volatile boolean stopRequested; + volatile ServiceTracker<RepositoryMount, RepositoryMount> mountTracker; + /** * Returns the default workspace, which may be <code>null</code> meaning to * use the repository provided default workspace. @@ -283,7 +292,30 @@ public abstract class AbstractSlingRepositoryManager { * @return The repository */ protected final Repository getRepository() { - return repository; + ServiceReference<RepositoryMount> ref = mountTracker != null ? mountTracker.getServiceReference() : null; + + Repository mountRepo = (ref != null ? mountTracker.getService(ref) : null); + Object mounts = ref != null ? ref.getProperty(RepositoryMount.MOUNT_POINTS_KEY) : null; + Set<String> mountPoints = new HashSet<>(); + + if (mounts != null) { + if (mounts instanceof String[]) { + for (String mount : ((String[]) mounts)) { + mountPoints.add(mount); + } + } + else { + mountPoints.add(mounts.toString()); + } + } + else { + mountPoints.add("/content/jcrmount"); + } + return mountRepo != null ? + repository instanceof JackrabbitRepository ? + new ProxyJackrabbitRepository((JackrabbitRepository) repository, (JackrabbitRepository) mountRepo, mountPoints) : + new ProxyRepository(repository, mountRepo, mountPoints) : + repository; } /** @@ -393,6 +425,9 @@ public abstract class AbstractSlingRepositoryManager { this.defaultWorkspace = config.defaultWorkspace; this.disableLoginAdministrative = config.disableLoginAdministrative; + this.mountTracker = new ServiceTracker<>(this.bundleContext, RepositoryMount.class, null); + this.mountTracker.open(); + this.repoInitializerTracker = new ServiceTracker<SlingRepositoryInitializer, SlingRepositoryInitializerInfo>(bundleContext, SlingRepositoryInitializer.class, new ServiceTrackerCustomizer<SlingRepositoryInitializer, SlingRepositoryInitializerInfo>() { @@ -574,6 +609,11 @@ public abstract class AbstractSlingRepositoryManager { startupThread = null; } + if (this.mountTracker != null) { + this.mountTracker.close(); + this.mountTracker = null; + } + // ensure the repository is really disposed off if (repository != null || isRepositoryServiceRegistered()) { log.info("stop: Repository still running, forcing shutdown"); @@ -604,7 +644,7 @@ public abstract class AbstractSlingRepositoryManager { this.destroy(this.masterSlingRepository); try { - disposeRepository(oldRepo); + disposeRepository(oldRepo instanceof ProxyRepository ? ((ProxyRepository) oldRepo).jcr : oldRepo); } catch (Throwable t) { log.info("stop: Uncaught problem disposing the repository", t); } diff --git a/src/main/java/org/apache/sling/jcr/base/internal/mount/ChainedIterator.java b/src/main/java/org/apache/sling/jcr/base/internal/mount/ChainedIterator.java new file mode 100644 index 0000000..015a920 --- /dev/null +++ b/src/main/java/org/apache/sling/jcr/base/internal/mount/ChainedIterator.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sling.jcr.base.internal.mount; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +public class ChainedIterator<T> implements Iterator<T> { + + private T nextElement; + + private final Iterator<Iterator<T>> iterators; + + private Iterator<T> currentIterator; + + public ChainedIterator(final Iterator<Iterator<T>> iterators) { + this.iterators = iterators; + } + + protected T seek() { + while (true) { + if (currentIterator == null) { + if (!iterators.hasNext()) { + return null; + } + currentIterator = iterators.next(); + continue; + } + if (currentIterator.hasNext()) { + return currentIterator.next(); + } else { + currentIterator = null; + } + } + } + + @Override + public boolean hasNext() { + if (nextElement == null) { + nextElement = seek(); + } + return nextElement != null; + } + + @Override + public T next() { + if (nextElement == null && !hasNext()) { + throw new NoSuchElementException(); + } + final T result = nextElement; + nextElement = null; + return result; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyAccessControlManager.java b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyAccessControlManager.java new file mode 100644 index 0000000..e82d362 --- /dev/null +++ b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyAccessControlManager.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sling.jcr.base.internal.mount; + +import javax.jcr.AccessDeniedException; +import javax.jcr.PathNotFoundException; +import javax.jcr.RepositoryException; +import javax.jcr.lock.LockException; +import javax.jcr.security.AccessControlException; +import javax.jcr.security.AccessControlManager; +import javax.jcr.security.AccessControlPolicy; +import javax.jcr.security.AccessControlPolicyIterator; +import javax.jcr.security.Privilege; +import javax.jcr.version.VersionException; + +public class ProxyAccessControlManager<T extends AccessControlManager> extends ProxyWrapper<T> implements AccessControlManager { + final T mount; + + public ProxyAccessControlManager(ProxySession<?> mountSession, T delegate, T mount) { + super(mountSession, delegate); + this.mount = mount; + } + + public Privilege[] getSupportedPrivileges(String absPath) throws PathNotFoundException, RepositoryException { + if (mountSession.isMount(absPath)) { + return mount.getSupportedPrivileges(absPath); + } + return delegate.getSupportedPrivileges(absPath); + } + + public Privilege privilegeFromName(String privilegeName) throws AccessControlException, RepositoryException { + try { + return delegate.privilegeFromName(privilegeName); + } catch (AccessControlException ex) { + return mount.privilegeFromName(privilegeName); + } + } + + public boolean hasPrivileges(String absPath, Privilege[] privileges) throws PathNotFoundException, RepositoryException { + if (mountSession.isMount(absPath)) { + return mount.hasPrivileges(absPath, privileges); + } + return delegate.hasPrivileges(absPath, privileges); + } + + public Privilege[] getPrivileges(String absPath) throws PathNotFoundException, RepositoryException { + if (mountSession.isMount(absPath)) { + return mount.getPrivileges(absPath); + } + return delegate.getPrivileges(absPath); + } + + public AccessControlPolicy[] getPolicies(String absPath) throws PathNotFoundException, AccessDeniedException, RepositoryException { + if (mountSession.isMount(absPath)) { + return mount.getPolicies(absPath); + } + return delegate.getPolicies(absPath); + } + + public AccessControlPolicy[] getEffectivePolicies(String absPath) throws PathNotFoundException, AccessDeniedException, RepositoryException { + if (mountSession.isMount(absPath)) { + return mount.getEffectivePolicies(absPath); + } + return delegate.getEffectivePolicies(absPath); + } + + public AccessControlPolicyIterator getApplicablePolicies(String absPath) throws PathNotFoundException, AccessDeniedException, RepositoryException { + if (mountSession.isMount(absPath)) { + return mount.getApplicablePolicies(absPath); + } + return delegate.getApplicablePolicies(absPath); + } + + public void setPolicy(String absPath, AccessControlPolicy policy) throws PathNotFoundException, AccessControlException, AccessDeniedException, LockException, VersionException, RepositoryException { + if (mountSession.isMountParent(absPath) || mountSession.isMount(absPath)) { + mount.setPolicy(absPath, policy); + } + if (!mountSession.isMount(absPath)) { + delegate.setPolicy(absPath, policy); + } + } + + public void removePolicy(String absPath, AccessControlPolicy policy) throws PathNotFoundException, AccessControlException, AccessDeniedException, LockException, VersionException, RepositoryException { + if (mountSession.isMountParent(absPath) || mountSession.isMount(absPath)) { + mount.removePolicy(absPath, policy); + } + if (!mountSession.isMount(absPath)) { + delegate.removePolicy(absPath, policy); + } + } +} diff --git a/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyItem.java b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyItem.java new file mode 100644 index 0000000..1207100 --- /dev/null +++ b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyItem.java @@ -0,0 +1,135 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sling.jcr.base.internal.mount; + +import javax.jcr.AccessDeniedException; +import javax.jcr.InvalidItemStateException; +import javax.jcr.Item; +import javax.jcr.ItemExistsException; +import javax.jcr.ItemNotFoundException; +import javax.jcr.ItemVisitor; +import javax.jcr.Node; +import javax.jcr.Property; +import javax.jcr.ReferentialIntegrityException; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.lock.LockException; +import javax.jcr.nodetype.ConstraintViolationException; +import javax.jcr.nodetype.NoSuchNodeTypeException; +import javax.jcr.version.VersionException; + +import org.apache.jackrabbit.oak.commons.PathUtils; + +public class ProxyItem<T extends Item> extends ProxyWrapper<T> implements Item { + public ProxyItem(ProxySession mountSession, T delegate) { + super(mountSession, delegate); + } + + @Override + public String getPath() throws RepositoryException { + return delegate.getPath(); + } + + @Override + public String getName() throws RepositoryException { + return delegate.getName(); + } + + @Override + public Item getAncestor(int depth) throws ItemNotFoundException, AccessDeniedException, RepositoryException { + return this.mountSession.getItem(this.delegate.getAncestor(depth).getPath()); + } + + @Override + public Node getParent() throws ItemNotFoundException, AccessDeniedException, RepositoryException { + + String parentPath; + + try { + parentPath = this.delegate.getParent().getPath(); + } catch (Exception ex) { + if (ex instanceof AccessDeniedException) { + throw (AccessDeniedException) ex; + } + parentPath = PathUtils.getParentPath(this.delegate.getPath()); + } + + return this.mountSession.getNode(parentPath); + } + + @Override + public int getDepth() throws RepositoryException { + return delegate.getDepth(); + } + + @Override + public Session getSession() throws RepositoryException { + return mountSession; + } + + @Override + public boolean isNode() { + return delegate.isNode(); + } + + @Override + public boolean isNew() { + return delegate.isNew(); + } + + @Override + public boolean isModified() { + return delegate.isModified(); + } + + @Override + public boolean isSame(Item otherItem) throws RepositoryException { + return delegate.isSame(this.mountSession.unwrap(otherItem)); + } + + @Override + public void accept(final ItemVisitor visitor) throws RepositoryException { + delegate.accept(new ItemVisitor() { + @Override + public void visit(Property property) throws RepositoryException { + visitor.visit(mountSession.wrap(property)); + } + + @Override + public void visit(Node node) throws RepositoryException { + visitor.visit(mountSession.wrap(node)); + } + }); + } + + @Override + public void save() throws AccessDeniedException, ItemExistsException, ConstraintViolationException, InvalidItemStateException, ReferentialIntegrityException, VersionException, LockException, NoSuchNodeTypeException, RepositoryException { + this.mountSession.save(); + } + + @Override + public void refresh(boolean keepChanges) throws InvalidItemStateException, RepositoryException { + this.mountSession.refresh(getPath(), delegate, keepChanges); + } + + @Override + public void remove() throws VersionException, LockException, ConstraintViolationException, AccessDeniedException, RepositoryException { + this.mountSession.removeItem(this.getPath()); + } +} diff --git a/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyJackrabbitAccessControlManager.java b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyJackrabbitAccessControlManager.java new file mode 100644 index 0000000..f810cd8 --- /dev/null +++ b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyJackrabbitAccessControlManager.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sling.jcr.base.internal.mount; + +import java.security.Principal; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Set; + +import javax.jcr.AccessDeniedException; +import javax.jcr.PathNotFoundException; +import javax.jcr.RepositoryException; +import javax.jcr.UnsupportedRepositoryOperationException; +import javax.jcr.security.AccessControlException; +import javax.jcr.security.AccessControlPolicy; +import javax.jcr.security.Privilege; + +import org.apache.jackrabbit.api.security.JackrabbitAccessControlManager; +import org.apache.jackrabbit.api.security.JackrabbitAccessControlPolicy; + +public class ProxyJackrabbitAccessControlManager extends ProxyAccessControlManager<JackrabbitAccessControlManager> implements JackrabbitAccessControlManager { + public ProxyJackrabbitAccessControlManager(ProxySession<?> mountSession, JackrabbitAccessControlManager delegate, JackrabbitAccessControlManager mount) { + super(mountSession, delegate, mount); + } + + public JackrabbitAccessControlPolicy[] getApplicablePolicies(Principal principal) throws AccessDeniedException, AccessControlException, UnsupportedRepositoryOperationException, RepositoryException { + List<JackrabbitAccessControlPolicy> result = new ArrayList<>(); + result.addAll(Arrays.asList(delegate.getApplicablePolicies(principal))); + result.addAll(Arrays.asList(mount.getApplicablePolicies(principal))); + return result.toArray(new JackrabbitAccessControlPolicy[0]); + } + + public JackrabbitAccessControlPolicy[] getPolicies(Principal principal) throws AccessDeniedException, AccessControlException, UnsupportedRepositoryOperationException, RepositoryException { + List<JackrabbitAccessControlPolicy> result = new ArrayList<>(); + result.addAll(Arrays.asList(delegate.getPolicies(principal))); + result.addAll(Arrays.asList(mount.getPolicies(principal))); + return result.toArray(new JackrabbitAccessControlPolicy[0]); + } + + public AccessControlPolicy[] getEffectivePolicies(Set<Principal> principals) throws AccessDeniedException, AccessControlException, UnsupportedRepositoryOperationException, RepositoryException { + List<AccessControlPolicy> result = new ArrayList<>(); + result.addAll(Arrays.asList(delegate.getEffectivePolicies(principals))); + result.addAll(Arrays.asList(mount.getEffectivePolicies(principals))); + return result.toArray(new AccessControlPolicy[0]); + } + + public boolean hasPrivileges(String absPath, Set<Principal> principals, Privilege[] privileges) throws PathNotFoundException, AccessDeniedException, RepositoryException { + if (mountSession.isMount(absPath)) { + return mount.hasPrivileges(absPath, principals, privileges); + } + return delegate.hasPrivileges(absPath, principals, privileges); + } + + public Privilege[] getPrivileges(String absPath, Set<Principal> principals) throws PathNotFoundException, AccessDeniedException, RepositoryException { + if (mountSession.isMount(absPath)) { + return mount.getPrivileges(absPath, principals); + } + return delegate.getPrivileges(absPath, principals); + } +} diff --git a/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyJackrabbitRepository.java b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyJackrabbitRepository.java new file mode 100644 index 0000000..42e2c2a --- /dev/null +++ b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyJackrabbitRepository.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sling.jcr.base.internal.mount; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import javax.jcr.Credentials; +import javax.jcr.LoginException; +import javax.jcr.NoSuchWorkspaceException; +import javax.jcr.RepositoryException; +import javax.jcr.Session; + +import org.apache.jackrabbit.api.JackrabbitRepository; +import org.apache.jackrabbit.api.JackrabbitSession; + +public class ProxyJackrabbitRepository extends ProxyRepository<JackrabbitRepository> implements JackrabbitRepository { + public ProxyJackrabbitRepository(JackrabbitRepository jcr, JackrabbitRepository mount, Set<String> mountPoint) { + super(jcr, mount, mountPoint); + } + + @Override + public Session login(Credentials credentials, String workspaceName, Map<String, Object> attributes) throws LoginException, NoSuchWorkspaceException, RepositoryException { + Session jcrSession = jcr.login(credentials, workspaceName, attributes); + + if (attributes == null) { + attributes = new HashMap<>(); + } + attributes.put(ProxyRepository.class.getPackage().getName() + ".PARENT_SESSION", jcrSession); + + Session mountSession = mount.login(credentials, workspaceName, attributes); + + return jcrSession instanceof JackrabbitSession ? + new ProxyJackrabbitSession(this, (JackrabbitSession) jcrSession, mountSession, this.mountPoints) : + new ProxySession<>(this, jcrSession, mountSession, this.mountPoints); + } + + @Override + public void shutdown() { + + } +} diff --git a/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyJackrabbitSession.java b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyJackrabbitSession.java new file mode 100644 index 0000000..97ee586 --- /dev/null +++ b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyJackrabbitSession.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sling.jcr.base.internal.mount; + +import java.util.HashSet; +import java.util.Set; +import javax.jcr.AccessDeniedException; +import javax.jcr.Item; +import javax.jcr.Node; +import javax.jcr.Property; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.UnsupportedRepositoryOperationException; +import javax.jcr.Workspace; + +import org.apache.jackrabbit.api.JackrabbitSession; +import org.apache.jackrabbit.api.JackrabbitWorkspace; +import org.apache.jackrabbit.api.security.principal.PrincipalManager; +import org.apache.jackrabbit.api.security.user.UserManager; + +public class ProxyJackrabbitSession extends ProxySession<JackrabbitSession> implements JackrabbitSession { + public ProxyJackrabbitSession(ProxyRepository repository, JackrabbitSession jcr, Session mount, Set<String> mountPoints) { + super(repository, jcr, mount, mountPoints); + } + + @Override + public Workspace getWorkspace() { + return new ProxyJackrabbitWorkspace(this, (JackrabbitWorkspace) this.jcr.getWorkspace(), (JackrabbitWorkspace) this.mount.getWorkspace()); + } + + public boolean hasPermission(String absPath, String... actions) throws RepositoryException { + if (isMount(absPath)) { + return ((JackrabbitSession) mount).hasPermission(absPath, actions); + } + return jcr.hasPermission(absPath, actions); + } + + public PrincipalManager getPrincipalManager() throws AccessDeniedException, UnsupportedRepositoryOperationException, RepositoryException { + return jcr.getPrincipalManager(); + } + + public UserManager getUserManager() throws AccessDeniedException, UnsupportedRepositoryOperationException, RepositoryException { + return new ProxyUserManager(this, jcr.getUserManager(), ((JackrabbitSession) mount).getUserManager()); + } + + public Item getItemOrNull(String absPath) throws RepositoryException { + if (super.itemExists(absPath)) { + return super.getItem(absPath); + } else { + return null; + } + } + + public Property getPropertyOrNull(String absPath) throws RepositoryException { + if (super.propertyExists(absPath)) { + return super.getProperty(absPath); + } else { + return null; + } + } + + public Node getNodeOrNull(String absPath) throws RepositoryException { + if (super.nodeExists(absPath)) { + return super.getNode(absPath); + } else { + return null; + } + } +} diff --git a/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyJackrabbitWorkspace.java b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyJackrabbitWorkspace.java new file mode 100644 index 0000000..03f5206 --- /dev/null +++ b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyJackrabbitWorkspace.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sling.jcr.base.internal.mount; + +import javax.jcr.AccessDeniedException; +import javax.jcr.RepositoryException; + +import org.apache.jackrabbit.api.JackrabbitWorkspace; +import org.apache.jackrabbit.api.security.authorization.PrivilegeManager; +import org.xml.sax.InputSource; + +public class ProxyJackrabbitWorkspace extends ProxyWorkspace<JackrabbitWorkspace> implements JackrabbitWorkspace { + public ProxyJackrabbitWorkspace(ProxySession mountSession, JackrabbitWorkspace delegate, JackrabbitWorkspace delegate2) { + super(mountSession, delegate, delegate2); + } + + @Override + public void createWorkspace(String workspaceName, InputSource workspaceTemplate) throws AccessDeniedException, RepositoryException { + this.delegate.createWorkspace(workspaceName, workspaceTemplate); + } + + @Override + public PrivilegeManager getPrivilegeManager() throws RepositoryException { + return new ProxyPrivilegeManager(mountSession, this.delegate.getPrivilegeManager(), this.delegate2.getPrivilegeManager()); + } +} diff --git a/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyLock.java b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyLock.java new file mode 100644 index 0000000..20f4316 --- /dev/null +++ b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyLock.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sling.jcr.base.internal.mount; + +import javax.jcr.Node; +import javax.jcr.RepositoryException; +import javax.jcr.lock.Lock; +import javax.jcr.lock.LockException; + +public class ProxyLock extends ProxyWrapper<Lock> implements Lock { + public ProxyLock(ProxySession<?> mountSession, Lock source) { + super(mountSession, source); + } + + @Override + public String getLockOwner() { + return delegate.getLockOwner(); + } + + @Override + public boolean isDeep() { + return delegate.isDeep(); + } + + @Override + public Node getNode() { + return this.mountSession.wrap(this.delegate.getNode()); + } + + @Override + public String getLockToken() { + return delegate.getLockToken(); + } + + @Override + public long getSecondsRemaining() throws RepositoryException { + return delegate.getSecondsRemaining(); + } + + @Override + public boolean isLive() throws RepositoryException { + return delegate.isLive(); + } + + @Override + public boolean isSessionScoped() { + return delegate.isSessionScoped(); + } + + @Override + public boolean isLockOwningSession() { + return delegate.isLockOwningSession(); + } + + @Override + public void refresh() throws LockException, RepositoryException { + delegate.refresh(); + } +} diff --git a/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyNamespaceRegistry.java b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyNamespaceRegistry.java new file mode 100644 index 0000000..7f70e2f --- /dev/null +++ b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyNamespaceRegistry.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sling.jcr.base.internal.mount; + +import javax.jcr.AccessDeniedException; +import javax.jcr.NamespaceException; +import javax.jcr.NamespaceRegistry; +import javax.jcr.RepositoryException; +import javax.jcr.UnsupportedRepositoryOperationException; + +public class ProxyNamespaceRegistry implements NamespaceRegistry { + private final NamespaceRegistry jcr; + private final NamespaceRegistry mount; + + public ProxyNamespaceRegistry(NamespaceRegistry jcr, NamespaceRegistry mount) { + this.jcr = jcr; + this.mount = mount; + } + + @Override + public void registerNamespace(String prefix, String uri) throws NamespaceException, UnsupportedRepositoryOperationException, AccessDeniedException, RepositoryException { + jcr.registerNamespace(prefix, uri); + mount.registerNamespace(prefix, uri); + } + + @Override + public void unregisterNamespace(String prefix) throws NamespaceException, UnsupportedRepositoryOperationException, AccessDeniedException, RepositoryException { + jcr.unregisterNamespace(prefix); + mount.unregisterNamespace(prefix); + } + + @Override + public String[] getPrefixes() throws RepositoryException { + return jcr.getPrefixes(); + } + + @Override + public String[] getURIs() throws RepositoryException { + return jcr.getURIs(); + } + + @Override + public String getURI(String prefix) throws NamespaceException, RepositoryException { + return jcr.getURI(prefix); + } + + @Override + public String getPrefix(String uri) throws NamespaceException, RepositoryException { + return jcr.getPrefix(uri); + } +} diff --git a/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyNode.java b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyNode.java new file mode 100644 index 0000000..80a3b2c --- /dev/null +++ b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyNode.java @@ -0,0 +1,413 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sling.jcr.base.internal.mount; + +import java.io.InputStream; +import java.math.BigDecimal; +import java.util.Calendar; + +import javax.jcr.AccessDeniedException; +import javax.jcr.Binary; +import javax.jcr.InvalidItemStateException; +import javax.jcr.InvalidLifecycleTransitionException; +import javax.jcr.Item; +import javax.jcr.ItemExistsException; +import javax.jcr.ItemNotFoundException; +import javax.jcr.MergeException; +import javax.jcr.NoSuchWorkspaceException; +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.PathNotFoundException; +import javax.jcr.Property; +import javax.jcr.PropertyIterator; +import javax.jcr.RepositoryException; +import javax.jcr.UnsupportedRepositoryOperationException; +import javax.jcr.Value; +import javax.jcr.ValueFormatException; +import javax.jcr.lock.Lock; +import javax.jcr.lock.LockException; +import javax.jcr.nodetype.ConstraintViolationException; +import javax.jcr.nodetype.NoSuchNodeTypeException; +import javax.jcr.nodetype.NodeDefinition; +import javax.jcr.nodetype.NodeType; +import javax.jcr.version.ActivityViolationException; +import javax.jcr.version.Version; +import javax.jcr.version.VersionException; +import javax.jcr.version.VersionHistory; + +public class ProxyNode extends ProxyItem<Node> implements Node { + public ProxyNode(ProxySession mountSession, Node node) { + super(mountSession, node); + } + + @Override + public Node addNode(String relPath) throws ItemExistsException, PathNotFoundException, VersionException, ConstraintViolationException, LockException, RepositoryException { + return mountSession.addNode(getPath(), concat(getPath(), relPath), relPath); + } + + @Override + public Node addNode(String relPath, String primaryNodeTypeName) throws ItemExistsException, PathNotFoundException, NoSuchNodeTypeException, LockException, VersionException, ConstraintViolationException, RepositoryException { + return mountSession.addNode(getPath(), concat(getPath(), relPath), relPath, primaryNodeTypeName); + } + + @Override + public void orderBefore(String srcChildRelPath, String destChildRelPath) throws UnsupportedRepositoryOperationException, VersionException, ConstraintViolationException, ItemNotFoundException, LockException, RepositoryException { + this.delegate.orderBefore(srcChildRelPath, destChildRelPath); + } + + @Override + public Property setProperty(String name, Value value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { + return this.mountSession.wrap(this.delegate.setProperty(name, value)); + } + + @Override + public Property setProperty(String name, Value value, int type) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { + return this.mountSession.wrap(this.delegate.setProperty(name, value, type)); + } + + @Override + public Property setProperty(String name, Value[] values) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { + return this.mountSession.wrap(this.delegate.setProperty(name, values)); + } + + @Override + public Property setProperty(String name, Value[] values, int type) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { + return this.mountSession.wrap(this.delegate.setProperty(name, values, type)); + } + + @Override + public Property setProperty(String name, String[] values) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { + return this.mountSession.wrap(this.delegate.setProperty(name, values)); + } + + @Override + public Property setProperty(String name, String[] values, int type) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { + return this.mountSession.wrap(this.delegate.setProperty(name, values, type)); + } + + @Override + public Property setProperty(String name, String value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { + return this.mountSession.wrap(this.delegate.setProperty(name, value)); + } + + @Override + public Property setProperty(String name, String value, int type) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { + return this.mountSession.wrap(this.delegate.setProperty(name, value, type)); + } + + @Override + public Property setProperty(String name, InputStream value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { + return this.mountSession.wrap(this.delegate.setProperty(name, value)); + } + + @Override + public Property setProperty(String name, Binary value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { + return this.mountSession.wrap(this.delegate.setProperty(name, value)); + } + + @Override + public Property setProperty(String name, boolean value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { + return this.mountSession.wrap(this.delegate.setProperty(name, value)); + } + + @Override + public Property setProperty(String name, double value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { + return this.mountSession.wrap(this.delegate.setProperty(name, value)); + } + + @Override + public Property setProperty(String name, BigDecimal value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { + return this.mountSession.wrap(this.delegate.setProperty(name, value)); + } + + @Override + public Property setProperty(String name, long value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { + return this.mountSession.wrap(this.delegate.setProperty(name, value)); + } + + @Override + public Property setProperty(String name, Calendar value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { + return this.mountSession.wrap(this.delegate.setProperty(name, value)); + } + + @Override + public Property setProperty(String name, Node value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { + return this.mountSession.wrap(this.delegate.setProperty(name, value)); + } + + @Override + public Node getNode(String relPath) throws PathNotFoundException, RepositoryException { + return this.mountSession.getNode(concat(getPath(), relPath)); + } + + @Override + public NodeIterator getNodes() throws RepositoryException { + return this.mountSession.getNodes(getPath(), this.delegate.getNodes()); + } + + @Override + public NodeIterator getNodes(String namePattern) throws RepositoryException { + return this.mountSession.getNodes(getPath(), this.delegate.getNodes(namePattern)); + } + + @Override + public NodeIterator getNodes(String[] nameGlobs) throws RepositoryException { + return this.mountSession.getNodes(getPath(), this.delegate.getNodes(nameGlobs)); + } + + @Override + public Property getProperty(String relPath) throws PathNotFoundException, RepositoryException { + return this.mountSession.wrap(this.delegate.getProperty(relPath)); + } + + @Override + public PropertyIterator getProperties() throws RepositoryException { + return this.mountSession.wrap(this.delegate.getProperties()); + } + + @Override + public PropertyIterator getProperties(String namePattern) throws RepositoryException { + return this.mountSession.wrap(this.delegate.getProperties(namePattern)); + } + + @Override + public PropertyIterator getProperties(String[] nameGlobs) throws RepositoryException { + return this.mountSession.wrap(this.delegate.getProperties(nameGlobs)); + } + + @Override + public Item getPrimaryItem() throws ItemNotFoundException, RepositoryException { + return this.mountSession.wrap(this.delegate.getPrimaryItem()); + } + + @Override + public String getUUID() throws UnsupportedRepositoryOperationException, RepositoryException { + return this.delegate.getUUID(); + } + + @Override + public String getIdentifier() throws RepositoryException { + return this.delegate.getIdentifier(); + } + + @Override + public int getIndex() throws RepositoryException { + return this.delegate.getIndex(); + } + + @Override + public PropertyIterator getReferences() throws RepositoryException { + return this.mountSession.wrap(this.delegate.getReferences()); + } + + @Override + public PropertyIterator getReferences(String name) throws RepositoryException { + return this.mountSession.wrap(this.delegate.getReferences(name)); + } + + @Override + public PropertyIterator getWeakReferences() throws RepositoryException { + return this.mountSession.wrap(this.delegate.getWeakReferences()); + } + + @Override + public PropertyIterator getWeakReferences(String name) throws RepositoryException { + return this.mountSession.wrap(this.delegate.getWeakReferences(name)); + } + + @Override + public boolean hasNode(String relPath) throws RepositoryException { + return this.mountSession.nodeExists(concat(getPath(), relPath)); + } + + @Override + public boolean hasProperty(String relPath) throws RepositoryException { + return this.mountSession.propertyExists(concat(getPath(), relPath)); + } + + @Override + public boolean hasNodes() throws RepositoryException { + return this.mountSession.hasNodes(this.delegate); + } + + @Override + public boolean hasProperties() throws RepositoryException { + return this.delegate.hasProperties(); + } + + @Override + public NodeType getPrimaryNodeType() throws RepositoryException { + return this.delegate.getPrimaryNodeType(); + } + + @Override + public NodeType[] getMixinNodeTypes() throws RepositoryException { + return this.delegate.getMixinNodeTypes(); + } + + @Override + public boolean isNodeType(String nodeTypeName) throws RepositoryException { + return this.delegate.isNodeType(nodeTypeName); + } + + @Override + public void setPrimaryType(String nodeTypeName) throws NoSuchNodeTypeException, VersionException, ConstraintViolationException, LockException, RepositoryException { + this.delegate.setPrimaryType(nodeTypeName); + } + + @Override + public void addMixin(String mixinName) throws NoSuchNodeTypeException, VersionException, ConstraintViolationException, LockException, RepositoryException { + this.delegate.addMixin(mixinName); + } + + @Override + public void removeMixin(String mixinName) throws NoSuchNodeTypeException, VersionException, ConstraintViolationException, LockException, RepositoryException { + this.delegate.removeMixin(mixinName); + } + + @Override + public boolean canAddMixin(String mixinName) throws NoSuchNodeTypeException, RepositoryException { + return this.delegate.canAddMixin(mixinName); + } + + @Override + public NodeDefinition getDefinition() throws RepositoryException { + return this.delegate.getDefinition(); + } + + @Override + public Version checkin() throws VersionException, UnsupportedRepositoryOperationException, InvalidItemStateException, LockException, RepositoryException { + return this.delegate.checkin(); + } + + @Override + public void checkout() throws UnsupportedRepositoryOperationException, LockException, ActivityViolationException, RepositoryException { + this.delegate.checkout(); + } + + @Override + public void doneMerge(Version version) throws VersionException, InvalidItemStateException, UnsupportedRepositoryOperationException, RepositoryException { + this.delegate.doneMerge(version); + } + + @Override + public void cancelMerge(Version version) throws VersionException, InvalidItemStateException, UnsupportedRepositoryOperationException, RepositoryException { + this.delegate.cancelMerge(version); + } + + @Override + public void update(String srcWorkspace) throws NoSuchWorkspaceException, AccessDeniedException, LockException, InvalidItemStateException, RepositoryException { + this.delegate.update(srcWorkspace); + } + + @Override + public NodeIterator merge(String srcWorkspace, boolean bestEffort) throws NoSuchWorkspaceException, AccessDeniedException, MergeException, LockException, InvalidItemStateException, RepositoryException { + return this.mountSession.wrap(this.delegate.merge(srcWorkspace, bestEffort)); + } + + @Override + public String getCorrespondingNodePath(String workspaceName) throws ItemNotFoundException, NoSuchWorkspaceException, AccessDeniedException, RepositoryException { + return this.delegate.getCorrespondingNodePath(workspaceName); + } + + @Override + public NodeIterator getSharedSet() throws RepositoryException { + return this.mountSession.wrap(this.delegate.getSharedSet()); + } + + @Override + public void removeSharedSet() throws VersionException, LockException, ConstraintViolationException, RepositoryException { + this.delegate.removeSharedSet(); + } + + @Override + public void removeShare() throws VersionException, LockException, ConstraintViolationException, RepositoryException { + this.delegate.removeShare(); + } + + @Override + public boolean isCheckedOut() throws RepositoryException { + return this.delegate.isCheckedOut(); + } + + @Override + public void restore(String versionName, boolean removeExisting) throws VersionException, ItemExistsException, UnsupportedRepositoryOperationException, LockException, InvalidItemStateException, RepositoryException { + this.delegate.restore(versionName, removeExisting); + } + + @Override + public void restore(Version version, boolean removeExisting) throws VersionException, ItemExistsException, InvalidItemStateException, UnsupportedRepositoryOperationException, LockException, RepositoryException { + this.delegate.restore(version, removeExisting); + } + + @Override + public void restore(Version version, String relPath, boolean removeExisting) throws PathNotFoundException, ItemExistsException, VersionException, ConstraintViolationException, UnsupportedRepositoryOperationException, LockException, InvalidItemStateException, RepositoryException { + this.delegate.restore(version, relPath, removeExisting); + } + + @Override + public void restoreByLabel(String versionLabel, boolean removeExisting) throws VersionException, ItemExistsException, UnsupportedRepositoryOperationException, LockException, InvalidItemStateException, RepositoryException { + this.delegate.restoreByLabel(versionLabel, removeExisting); + } + + @Override + public VersionHistory getVersionHistory() throws UnsupportedRepositoryOperationException, RepositoryException { + return this.delegate.getVersionHistory(); + } + + @Override + public Version getBaseVersion() throws UnsupportedRepositoryOperationException, RepositoryException { + return this.delegate.getBaseVersion(); + } + + @Override + public Lock lock(boolean isDeep, boolean isSessionScoped) throws UnsupportedRepositoryOperationException, LockException, AccessDeniedException, InvalidItemStateException, RepositoryException { + return this.mountSession.wrap(this.delegate.lock(isDeep, isSessionScoped)); + } + + @Override + public Lock getLock() throws UnsupportedRepositoryOperationException, LockException, AccessDeniedException, RepositoryException { + return this.mountSession.wrap(this.delegate.getLock()); + } + + @Override + public void unlock() throws UnsupportedRepositoryOperationException, LockException, AccessDeniedException, InvalidItemStateException, RepositoryException { + this.delegate.unlock(); + } + + @Override + public boolean holdsLock() throws RepositoryException { + return this.delegate.holdsLock(); + } + + @Override + public boolean isLocked() throws RepositoryException { + return this.delegate.isLocked(); + } + + @Override + public void followLifecycleTransition(String transition) throws UnsupportedRepositoryOperationException, InvalidLifecycleTransitionException, RepositoryException { + this.delegate.followLifecycleTransition(transition); + } + + @Override + public String[] getAllowedLifecycleTransistions() throws UnsupportedRepositoryOperationException, RepositoryException { + return this.delegate.getAllowedLifecycleTransistions(); + } +} diff --git a/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyNodeTypeManager.java b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyNodeTypeManager.java new file mode 100644 index 0000000..29d378e --- /dev/null +++ b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyNodeTypeManager.java @@ -0,0 +1,111 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sling.jcr.base.internal.mount; + +import javax.jcr.RepositoryException; +import javax.jcr.UnsupportedRepositoryOperationException; +import javax.jcr.nodetype.InvalidNodeTypeDefinitionException; +import javax.jcr.nodetype.NoSuchNodeTypeException; +import javax.jcr.nodetype.NodeDefinitionTemplate; +import javax.jcr.nodetype.NodeType; +import javax.jcr.nodetype.NodeTypeDefinition; +import javax.jcr.nodetype.NodeTypeExistsException; +import javax.jcr.nodetype.NodeTypeIterator; +import javax.jcr.nodetype.NodeTypeManager; +import javax.jcr.nodetype.NodeTypeTemplate; +import javax.jcr.nodetype.PropertyDefinitionTemplate; + +public class ProxyNodeTypeManager implements NodeTypeManager { + private final NodeTypeManager nodeTypeManager; + private final NodeTypeManager nodeTypeManager1; + + public ProxyNodeTypeManager(NodeTypeManager nodeTypeManager, NodeTypeManager nodeTypeManager1) { + this.nodeTypeManager = nodeTypeManager; + this.nodeTypeManager1 = nodeTypeManager1; + } + + @Override + public NodeType getNodeType(String nodeTypeName) throws NoSuchNodeTypeException, RepositoryException { + return nodeTypeManager.getNodeType(nodeTypeName); + } + + @Override + public boolean hasNodeType(String name) throws RepositoryException { + return nodeTypeManager.hasNodeType(name); + } + + @Override + public NodeTypeIterator getAllNodeTypes() throws RepositoryException { + return nodeTypeManager.getAllNodeTypes(); + } + + @Override + public NodeTypeIterator getPrimaryNodeTypes() throws RepositoryException { + return nodeTypeManager.getPrimaryNodeTypes(); + } + + @Override + public NodeTypeIterator getMixinNodeTypes() throws RepositoryException { + return nodeTypeManager.getMixinNodeTypes(); + } + + @Override + public NodeTypeTemplate createNodeTypeTemplate() throws UnsupportedRepositoryOperationException, RepositoryException { + return nodeTypeManager.createNodeTypeTemplate(); + } + + @Override + public NodeTypeTemplate createNodeTypeTemplate(NodeTypeDefinition ntd) throws UnsupportedRepositoryOperationException, RepositoryException { + return nodeTypeManager.createNodeTypeTemplate(ntd); + } + + @Override + public NodeDefinitionTemplate createNodeDefinitionTemplate() throws UnsupportedRepositoryOperationException, RepositoryException { + return nodeTypeManager.createNodeDefinitionTemplate(); + } + + @Override + public PropertyDefinitionTemplate createPropertyDefinitionTemplate() throws UnsupportedRepositoryOperationException, RepositoryException { + return nodeTypeManager.createPropertyDefinitionTemplate(); + } + + @Override + public NodeType registerNodeType(NodeTypeDefinition ntd, boolean allowUpdate) throws InvalidNodeTypeDefinitionException, NodeTypeExistsException, UnsupportedRepositoryOperationException, RepositoryException { + nodeTypeManager1.registerNodeType(ntd, allowUpdate); + return nodeTypeManager.registerNodeType(ntd, allowUpdate); + } + + @Override + public NodeTypeIterator registerNodeTypes(NodeTypeDefinition[] ntds, boolean allowUpdate) throws InvalidNodeTypeDefinitionException, NodeTypeExistsException, UnsupportedRepositoryOperationException, RepositoryException { + nodeTypeManager1.registerNodeTypes(ntds, allowUpdate); + return nodeTypeManager.registerNodeTypes(ntds, allowUpdate); + } + + @Override + public void unregisterNodeType(String name) throws UnsupportedRepositoryOperationException, NoSuchNodeTypeException, RepositoryException { + nodeTypeManager.unregisterNodeType(name); + nodeTypeManager1.unregisterNodeType(name); + } + + @Override + public void unregisterNodeTypes(String[] names) throws UnsupportedRepositoryOperationException, NoSuchNodeTypeException, RepositoryException { + nodeTypeManager.unregisterNodeTypes(names); + nodeTypeManager1.unregisterNodeTypes(names); + } +} diff --git a/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyPrivilegeManager.java b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyPrivilegeManager.java new file mode 100644 index 0000000..ae4eda6 --- /dev/null +++ b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyPrivilegeManager.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sling.jcr.base.internal.mount; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.jcr.AccessDeniedException; +import javax.jcr.NamespaceException; +import javax.jcr.RepositoryException; +import javax.jcr.security.AccessControlException; +import javax.jcr.security.Privilege; + +import org.apache.jackrabbit.api.security.authorization.PrivilegeManager; + +public class ProxyPrivilegeManager extends ProxyWrapper<PrivilegeManager> implements PrivilegeManager { + private final PrivilegeManager mount; + + public ProxyPrivilegeManager(ProxySession<?> mountSession, PrivilegeManager delegate, PrivilegeManager mount) { + super(mountSession, delegate); + this.mount = mount; + } + + public Privilege[] getRegisteredPrivileges() throws RepositoryException { + List<Privilege> result = new ArrayList<>(); + result.addAll(Arrays.asList(delegate.getRegisteredPrivileges())); + + result.addAll(Arrays.asList(mount.getRegisteredPrivileges())); + + return result.toArray(new Privilege[0]); + } + + public Privilege getPrivilege(String privilegeName) throws AccessControlException, RepositoryException { + try { + return mount.getPrivilege(privilegeName); + } catch (AccessControlException ex) { + return delegate.getPrivilege(privilegeName); + } + } + + public Privilege registerPrivilege(String privilegeName, boolean isAbstract, String[] declaredAggregateNames) throws AccessDeniedException, NamespaceException, RepositoryException { + mount.registerPrivilege(privilegeName, isAbstract, declaredAggregateNames); + return delegate.registerPrivilege(privilegeName, isAbstract, declaredAggregateNames); + } +} diff --git a/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyProperty.java b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyProperty.java new file mode 100644 index 0000000..50cd8f9 --- /dev/null +++ b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyProperty.java @@ -0,0 +1,157 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sling.jcr.base.internal.mount; + +import java.io.InputStream; +import java.math.BigDecimal; +import java.util.Calendar; + +import javax.jcr.Binary; +import javax.jcr.ItemNotFoundException; +import javax.jcr.Node; +import javax.jcr.Property; +import javax.jcr.RepositoryException; +import javax.jcr.Value; +import javax.jcr.ValueFormatException; +import javax.jcr.lock.LockException; +import javax.jcr.nodetype.ConstraintViolationException; +import javax.jcr.nodetype.PropertyDefinition; +import javax.jcr.version.VersionException; + +public class ProxyProperty extends ProxyItem<Property> implements Property { + public ProxyProperty(ProxySession mountSession, Property delegate) { + super(mountSession, delegate); + } + + public void setValue(Value value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { + delegate.setValue(value); + } + + public void setValue(Value[] values) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { + delegate.setValue(values); + } + + public void setValue(String value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { + delegate.setValue(value); + } + + public void setValue(String[] values) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { + delegate.setValue(values); + } + + public void setValue(InputStream value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { + delegate.setValue(value); + } + + public void setValue(Binary value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { + delegate.setValue(value); + } + + public void setValue(long value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { + delegate.setValue(value); + } + + public void setValue(double value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { + delegate.setValue(value); + } + + public void setValue(BigDecimal value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { + delegate.setValue(value); + } + + public void setValue(Calendar value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { + delegate.setValue(value); + } + + public void setValue(boolean value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { + delegate.setValue(value); + } + + public void setValue(Node value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { + delegate.setValue(value); + } + + public Value getValue() throws ValueFormatException, RepositoryException { + return delegate.getValue(); + } + + public Value[] getValues() throws ValueFormatException, RepositoryException { + return delegate.getValues(); + } + + public String getString() throws ValueFormatException, RepositoryException { + return delegate.getString(); + } + + public InputStream getStream() throws ValueFormatException, RepositoryException { + return delegate.getStream(); + } + + public Binary getBinary() throws ValueFormatException, RepositoryException { + return delegate.getBinary(); + } + + public long getLong() throws ValueFormatException, RepositoryException { + return delegate.getLong(); + } + + public double getDouble() throws ValueFormatException, RepositoryException { + return delegate.getDouble(); + } + + public BigDecimal getDecimal() throws ValueFormatException, RepositoryException { + return delegate.getDecimal(); + } + + public Calendar getDate() throws ValueFormatException, RepositoryException { + return delegate.getDate(); + } + + public boolean getBoolean() throws ValueFormatException, RepositoryException { + return delegate.getBoolean(); + } + + public Node getNode() throws ItemNotFoundException, ValueFormatException, RepositoryException { + return this.mountSession.getNode(delegate.getNode().getPath()); + } + + public Property getProperty() throws ItemNotFoundException, ValueFormatException, RepositoryException { + return this.mountSession.getProperty(delegate.getProperty().getPath()); + } + + public long getLength() throws ValueFormatException, RepositoryException { + return delegate.getLength(); + } + + public long[] getLengths() throws ValueFormatException, RepositoryException { + return delegate.getLengths(); + } + + public PropertyDefinition getDefinition() throws RepositoryException { + return delegate.getDefinition(); + } + + public int getType() throws RepositoryException { + return delegate.getType(); + } + + public boolean isMultiple() throws RepositoryException { + return delegate.isMultiple(); + } +} diff --git a/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyQuery.java b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyQuery.java new file mode 100644 index 0000000..770f7a5 --- /dev/null +++ b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyQuery.java @@ -0,0 +1,233 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sling.jcr.base.internal.mount; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javax.jcr.ItemExistsException; +import javax.jcr.ItemNotFoundException; +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.PathNotFoundException; +import javax.jcr.RepositoryException; +import javax.jcr.UnsupportedRepositoryOperationException; +import javax.jcr.Value; +import javax.jcr.lock.LockException; +import javax.jcr.nodetype.ConstraintViolationException; +import javax.jcr.query.InvalidQueryException; +import javax.jcr.query.Query; +import javax.jcr.query.QueryResult; +import javax.jcr.query.Row; +import javax.jcr.query.RowIterator; +import javax.jcr.version.VersionException; + +public class ProxyQuery extends ProxyWrapper<Query> implements Query { + private final Query delegate2; + + public ProxyQuery(ProxySession<?> mountSession, Query delegate, Query delegate2) { + super(mountSession, delegate); + this.delegate2 = delegate2; + } + + public QueryResult execute() throws InvalidQueryException, RepositoryException { + final QueryResult result1 = delegate.execute(); + QueryResult result2temp = null; + if (delegate2 != null) { + result2temp = delegate2.execute(); + } + final QueryResult result2 = result2temp; + + return this.mountSession.wrap(new QueryResult() { + @Override + public String[] getColumnNames() throws RepositoryException { + return result1.getColumnNames(); + } + + @Override + public RowIterator getRows() throws RepositoryException { + final RowIterator i1 = result1.getRows(); + RowIterator i2 = null; + if (result2 != null) { + i2 = result2.getRows(); + } + if ( i2 == null || !i2.hasNext() ) { + return i1; + } + if ( !i1.hasNext() ) { + return i2; + } + final List<RowIterator> list = new ArrayList<>(); + list.add(i1); + list.add(i2); + @SuppressWarnings({ "unchecked", "rawtypes" }) + final Iterator<Row> iter = new ChainedIterator(list.iterator()); + return new RowIterator() { + + @Override + public Object next() { + return iter.next(); + } + + @Override + public boolean hasNext() { + return iter.hasNext(); + } + + @Override + public void skip(long skipNum) { + // TODO Auto-generated method stub + + } + + @Override + public long getSize() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public long getPosition() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public Row nextRow() { + return iter.next(); + } + }; + } + + @Override + public NodeIterator getNodes() throws RepositoryException { + final NodeIterator i1 = result1.getNodes(); + NodeIterator i2 = null; + if (result2 != null) { + i2 = result2.getNodes(); + } + if ( i2 == null || !i2.hasNext() ) { + return i1; + } + if ( !i1.hasNext() ) { + return i2; + } + final List<NodeIterator> list = new ArrayList<>(); + list.add(i1); + list.add(i2); + @SuppressWarnings({ "unchecked", "rawtypes" }) + final Iterator<Node> iter = new ChainedIterator(list.iterator()); + return new NodeIterator() { + + @Override + public Object next() { + return iter.next(); + } + + @Override + public boolean hasNext() { + return iter.hasNext(); + } + + @Override + public void skip(long skipNum) { + // TODO Auto-generated method stub + + } + + @Override + public long getSize() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public long getPosition() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public Node nextNode() { + return iter.next(); + } + }; + } + + @Override + public String[] getSelectorNames() throws RepositoryException { + return result1.getSelectorNames(); + } + }); + } + + public void setLimit(long limit) { + delegate.setLimit(limit); + if (delegate2 != null) { + delegate2.setLimit(limit); + } + } + + public void setOffset(long offset) { + delegate.setOffset(offset); + if (delegate2 != null) { + delegate2.setOffset(2); + } + } + + public String getStatement() { + return delegate.getStatement(); + } + + public String getLanguage() { + return delegate.getLanguage(); + } + + public String getStoredQueryPath() throws ItemNotFoundException, RepositoryException { + try { + return delegate.getStoredQueryPath(); + } catch (ItemNotFoundException ex) { + try { + if (delegate2 != null) { + return delegate2.getStoredQueryPath(); + } else { + return ""; + } + } catch (ItemNotFoundException ignore) { + throw ex; + } + } + } + + public Node storeAsNode(String absPath) throws ItemExistsException, PathNotFoundException, VersionException, ConstraintViolationException, LockException, UnsupportedRepositoryOperationException, RepositoryException { + return this.mountSession.wrap(this.mountSession.isMount(absPath) ? delegate2.storeAsNode(absPath) : delegate.storeAsNode(absPath)); + } + + public void bindValue(String varName, Value value) throws IllegalArgumentException, RepositoryException { + delegate.bindValue(varName, value); + if (delegate2 != null) { + delegate2.bindValue(varName, value); + } + } + + public String[] getBindVariableNames() throws RepositoryException { + return delegate.getBindVariableNames(); + } +} diff --git a/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyQueryManager.java b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyQueryManager.java new file mode 100644 index 0000000..ed897ae --- /dev/null +++ b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyQueryManager.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sling.jcr.base.internal.mount; + +import javax.jcr.Node; +import javax.jcr.RepositoryException; +import javax.jcr.query.InvalidQueryException; +import javax.jcr.query.Query; +import javax.jcr.query.QueryManager; +import javax.jcr.query.qom.QueryObjectModelFactory; + +public class ProxyQueryManager extends ProxyWrapper<QueryManager> implements QueryManager { + private final QueryManager delegate2; + + public ProxyQueryManager(ProxySession<?> mountSession, QueryManager delegate, QueryManager delegate2) { + super(mountSession, delegate); + this.delegate2 = delegate2; + } + + @Override + public Query createQuery(String statement, String language) throws InvalidQueryException, RepositoryException { + return new ProxyQuery(this.mountSession, delegate.createQuery(statement, language), delegate2.createQuery(statement, language)); + } + + @Override + public QueryObjectModelFactory getQOMFactory() { + return new ProxyQueryObjectModelFactory(this.mountSession, delegate.getQOMFactory(), delegate2.getQOMFactory()); + } + + @Override + public Query getQuery(Node node) throws InvalidQueryException, RepositoryException { + return this.mountSession.wrap(delegate.getQuery(this.mountSession.unwrap(node))); + } + + @Override + public String[] getSupportedQueryLanguages() throws RepositoryException { + return delegate.getSupportedQueryLanguages(); + } +} diff --git a/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyQueryObjectModel.java b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyQueryObjectModel.java new file mode 100644 index 0000000..4cc6ecc --- /dev/null +++ b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyQueryObjectModel.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sling.jcr.base.internal.mount; + +import javax.jcr.query.qom.Column; +import javax.jcr.query.qom.Constraint; +import javax.jcr.query.qom.Ordering; +import javax.jcr.query.qom.QueryObjectModel; +import javax.jcr.query.qom.Source; + +public class ProxyQueryObjectModel extends ProxyQuery implements QueryObjectModel { + public ProxyQueryObjectModel(ProxySession<?> mountSession, QueryObjectModel delegate, QueryObjectModel delegate2) { + super(mountSession, delegate, delegate2); + } + + public Source getSource() { + return ((QueryObjectModel) delegate).getSource(); + } + + public Constraint getConstraint() { + return ((QueryObjectModel) delegate).getConstraint(); + } + + public Ordering[] getOrderings() { + return ((QueryObjectModel) delegate).getOrderings(); + } + + public Column[] getColumns() { + return ((QueryObjectModel) delegate).getColumns(); + } +} diff --git a/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyQueryObjectModelFactory.java b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyQueryObjectModelFactory.java new file mode 100644 index 0000000..35d2aa0 --- /dev/null +++ b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyQueryObjectModelFactory.java @@ -0,0 +1,183 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sling.jcr.base.internal.mount; + +import javax.jcr.RepositoryException; +import javax.jcr.Value; +import javax.jcr.query.InvalidQueryException; +import javax.jcr.query.qom.And; +import javax.jcr.query.qom.BindVariableValue; +import javax.jcr.query.qom.ChildNode; +import javax.jcr.query.qom.ChildNodeJoinCondition; +import javax.jcr.query.qom.Column; +import javax.jcr.query.qom.Comparison; +import javax.jcr.query.qom.Constraint; +import javax.jcr.query.qom.DescendantNode; +import javax.jcr.query.qom.DescendantNodeJoinCondition; +import javax.jcr.query.qom.DynamicOperand; +import javax.jcr.query.qom.EquiJoinCondition; +import javax.jcr.query.qom.FullTextSearch; +import javax.jcr.query.qom.FullTextSearchScore; +import javax.jcr.query.qom.Join; +import javax.jcr.query.qom.JoinCondition; +import javax.jcr.query.qom.Length; +import javax.jcr.query.qom.Literal; +import javax.jcr.query.qom.LowerCase; +import javax.jcr.query.qom.NodeLocalName; +import javax.jcr.query.qom.NodeName; +import javax.jcr.query.qom.Not; +import javax.jcr.query.qom.Or; +import javax.jcr.query.qom.Ordering; +import javax.jcr.query.qom.PropertyExistence; +import javax.jcr.query.qom.PropertyValue; +import javax.jcr.query.qom.QueryObjectModel; +import javax.jcr.query.qom.QueryObjectModelFactory; +import javax.jcr.query.qom.SameNode; +import javax.jcr.query.qom.SameNodeJoinCondition; +import javax.jcr.query.qom.Selector; +import javax.jcr.query.qom.Source; +import javax.jcr.query.qom.StaticOperand; +import javax.jcr.query.qom.UpperCase; + +public class ProxyQueryObjectModelFactory extends ProxyWrapper<QueryObjectModelFactory> implements QueryObjectModelFactory { + private final QueryObjectModelFactory delegate2; + + public ProxyQueryObjectModelFactory(ProxySession<?> mountSession, QueryObjectModelFactory delegate, QueryObjectModelFactory delegate2) { + super(mountSession, delegate); + this.delegate2 = delegate2; + } + + public QueryObjectModel createQuery(Source source, Constraint constraint, Ordering[] orderings, Column[] columns) throws InvalidQueryException, RepositoryException { + if (delegate2 != null) { + return new ProxyQueryObjectModel(this.mountSession, delegate.createQuery(source, constraint, orderings, columns), + delegate2.createQuery(source, constraint, orderings, columns)); + } else { + return new ProxyQueryObjectModel(this.mountSession, delegate.createQuery(source, constraint, orderings, columns), + null); + } + } + + public Selector selector(String nodeTypeName, String selectorName) throws InvalidQueryException, RepositoryException { + return delegate.selector(nodeTypeName, selectorName); + } + + public Join join(Source left, Source right, String joinType, JoinCondition joinCondition) throws InvalidQueryException, RepositoryException { + return delegate.join(left, right, joinType, joinCondition); + } + + public EquiJoinCondition equiJoinCondition(String selector1Name, String property1Name, String selector2Name, String property2Name) throws InvalidQueryException, RepositoryException { + return delegate.equiJoinCondition(selector1Name, property1Name, selector2Name, property2Name); + } + + public SameNodeJoinCondition sameNodeJoinCondition(String selector1Name, String selector2Name, String selector2Path) throws InvalidQueryException, RepositoryException { + return delegate.sameNodeJoinCondition(selector1Name, selector2Name, selector2Path); + } + + public ChildNodeJoinCondition childNodeJoinCondition(String childSelectorName, String parentSelectorName) throws InvalidQueryException, RepositoryException { + return delegate.childNodeJoinCondition(childSelectorName, parentSelectorName); + } + + public DescendantNodeJoinCondition descendantNodeJoinCondition(String descendantSelectorName, String ancestorSelectorName) throws InvalidQueryException, RepositoryException { + return delegate.descendantNodeJoinCondition(descendantSelectorName, ancestorSelectorName); + } + + public And and(Constraint constraint1, Constraint constraint2) throws InvalidQueryException, RepositoryException { + return delegate.and(constraint1, constraint2); + } + + public Or or(Constraint constraint1, Constraint constraint2) throws InvalidQueryException, RepositoryException { + return delegate.or(constraint1, constraint2); + } + + public Not not(Constraint constraint) throws InvalidQueryException, RepositoryException { + return delegate.not(constraint); + } + + public Comparison comparison(DynamicOperand operand1, String operator, StaticOperand operand2) throws InvalidQueryException, RepositoryException { + return delegate.comparison(operand1, operator, operand2); + } + + public PropertyExistence propertyExistence(String selectorName, String propertyName) throws InvalidQueryException, RepositoryException { + return delegate.propertyExistence(selectorName, propertyName); + } + + public FullTextSearch fullTextSearch(String selectorName, String propertyName, StaticOperand fullTextSearchExpression) throws InvalidQueryException, RepositoryException { + return delegate.fullTextSearch(selectorName, propertyName, fullTextSearchExpression); + } + + public SameNode sameNode(String selectorName, String path) throws InvalidQueryException, RepositoryException { + return delegate.sameNode(selectorName, path); + } + + public ChildNode childNode(String selectorName, String path) throws InvalidQueryException, RepositoryException { + return delegate.childNode(selectorName, path); + } + + public DescendantNode descendantNode(String selectorName, String path) throws InvalidQueryException, RepositoryException { + return delegate.descendantNode(selectorName, path); + } + + public PropertyValue propertyValue(String selectorName, String propertyName) throws InvalidQueryException, RepositoryException { + return delegate.propertyValue(selectorName, propertyName); + } + + public Length length(PropertyValue propertyValue) throws InvalidQueryException, RepositoryException { + return delegate.length(propertyValue); + } + + public NodeName nodeName(String selectorName) throws InvalidQueryException, RepositoryException { + return delegate.nodeName(selectorName); + } + + public NodeLocalName nodeLocalName(String selectorName) throws InvalidQueryException, RepositoryException { + return delegate.nodeLocalName(selectorName); + } + + public FullTextSearchScore fullTextSearchScore(String selectorName) throws InvalidQueryException, RepositoryException { + return delegate.fullTextSearchScore(selectorName); + } + + public LowerCase lowerCase(DynamicOperand operand) throws InvalidQueryException, RepositoryException { + return delegate.lowerCase(operand); + } + + public UpperCase upperCase(DynamicOperand operand) throws InvalidQueryException, RepositoryException { + return delegate.upperCase(operand); + } + + public BindVariableValue bindVariable(String bindVariableName) throws InvalidQueryException, RepositoryException { + return delegate.bindVariable(bindVariableName); + } + + public Literal literal(Value literalValue) throws InvalidQueryException, RepositoryException { + return delegate.literal(literalValue); + } + + public Ordering ascending(DynamicOperand operand) throws InvalidQueryException, RepositoryException { + return delegate.ascending(operand); + } + + public Ordering descending(DynamicOperand operand) throws InvalidQueryException, RepositoryException { + return delegate.descending(operand); + } + + public Column column(String selectorName, String propertyName, String columnName) throws InvalidQueryException, RepositoryException { + return delegate.column(selectorName, propertyName, columnName); + } +} diff --git a/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyQueryResult.java b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyQueryResult.java new file mode 100644 index 0000000..ee9e1fd --- /dev/null +++ b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyQueryResult.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sling.jcr.base.internal.mount; + +import javax.jcr.NodeIterator; +import javax.jcr.RepositoryException; +import javax.jcr.query.QueryResult; +import javax.jcr.query.RowIterator; + +public class ProxyQueryResult extends ProxyWrapper<QueryResult> implements QueryResult { + public ProxyQueryResult(ProxySession<?> mountSession, QueryResult delegate) { + super(mountSession, delegate); + } + + public String[] getColumnNames() throws RepositoryException { + return delegate.getColumnNames(); + } + + public RowIterator getRows() throws RepositoryException { + return this.mountSession.wrap(delegate.getRows()); + } + + public NodeIterator getNodes() throws RepositoryException { + return this.mountSession.wrap(delegate.getNodes()); + } + + public String[] getSelectorNames() throws RepositoryException { + return delegate.getSelectorNames(); + } +} diff --git a/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyRepository.java b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyRepository.java new file mode 100644 index 0000000..40b685c --- /dev/null +++ b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyRepository.java @@ -0,0 +1,133 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sling.jcr.base.internal.mount; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import javax.jcr.Credentials; +import javax.jcr.LoginException; +import javax.jcr.NoSuchWorkspaceException; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.SimpleCredentials; +import javax.jcr.Value; + +import org.apache.jackrabbit.api.JackrabbitRepository; +import org.apache.jackrabbit.api.JackrabbitSession; +import org.apache.sling.jcr.base.spi.RepositoryMount; + +public class ProxyRepository<T extends Repository> implements Repository { + public final T jcr; + final T mount; + final Set<String> mountPoints; + + public ProxyRepository(T jcr, T mount, Set<String> mountPoint) { + this.jcr = jcr; + this.mount = mount; + this.mountPoints = new HashSet<>(mountPoint); + } + + + @Override + public String[] getDescriptorKeys() { + return jcr.getDescriptorKeys(); + } + + @Override + public boolean isStandardDescriptor(String key) { + return jcr.isStandardDescriptor(key); + } + + @Override + public boolean isSingleValueDescriptor(String key) { + return jcr.isSingleValueDescriptor(key); + } + + @Override + public Value getDescriptorValue(String key) { + return jcr.getDescriptorValue(key); + } + + @Override + public Value[] getDescriptorValues(String key) { + return jcr.getDescriptorValues(key); + } + + @Override + public String getDescriptor(String key) { + return jcr.getDescriptor(key); + } + + @Override + public Session login(Credentials credentials, String workspaceName) throws LoginException, NoSuchWorkspaceException, RepositoryException { + Session jcrSession = jcr.login(credentials, workspaceName); + + Session mountSession; + if (mount instanceof JackrabbitRepository) { + Map<String, Object> attributes = new HashMap<>(); + attributes.put(RepositoryMount.PARENT_SESSION_KEY, jcrSession); + mountSession = ((JackrabbitRepository) mount).login(credentials, workspaceName, attributes); + } + else { + mountSession = mount.login(credentials, workspaceName); + } + return jcrSession instanceof JackrabbitSession ? + new ProxyJackrabbitSession(this, (JackrabbitSession) jcrSession, mountSession, this.mountPoints) : + new ProxySession<>(this, jcrSession, mountSession, this.mountPoints); + } + + @Override + public Session login(Credentials credentials) throws LoginException, RepositoryException { + return login(credentials, null); + } + + @Override + public Session login(String workspaceName) throws LoginException, NoSuchWorkspaceException, RepositoryException { + return login(null, workspaceName); + } + + @Override + public Session login() throws LoginException, RepositoryException { + return login(null, null); + } + + public Session wrap(Session session) throws RepositoryException { + if (session instanceof ProxySession) { + return session; + } + + Map<String, Object> attributes = new HashMap<>(); + attributes.put(RepositoryMount.PARENT_SESSION_KEY, session); + Session mountSession = ((JackrabbitRepository) mount).login(new SimpleCredentials(session.getUserID(), new char[0]),session.getWorkspace().getName(), attributes ); + + return session instanceof JackrabbitSession ? + new ProxyJackrabbitSession(this, (JackrabbitSession) session, mountSession, this.mountPoints) : + new ProxySession<>(this, session, mountSession, this.mountPoints); + } + + Session impersonate(Credentials credentials, Session jcr, Session mount) throws RepositoryException { + return jcr instanceof JackrabbitSession ? + new ProxyJackrabbitSession(this, (JackrabbitSession) jcr.impersonate(credentials), mount.impersonate(credentials), this.mountPoints) : + new ProxySession<>(this, jcr.impersonate(credentials), mount.impersonate(credentials), this.mountPoints); + } +} diff --git a/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxySession.java b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxySession.java new file mode 100644 index 0000000..efbc475 --- /dev/null +++ b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxySession.java @@ -0,0 +1,615 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sling.jcr.base.internal.mount; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.AccessControlException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import javax.jcr.AccessDeniedException; +import javax.jcr.Credentials; +import javax.jcr.InvalidItemStateException; +import javax.jcr.InvalidSerializedDataException; +import javax.jcr.Item; +import javax.jcr.ItemExistsException; +import javax.jcr.ItemNotFoundException; +import javax.jcr.LoginException; +import javax.jcr.NamespaceException; +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.PathNotFoundException; +import javax.jcr.Property; +import javax.jcr.PropertyIterator; +import javax.jcr.ReferentialIntegrityException; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.UnsupportedRepositoryOperationException; +import javax.jcr.Value; +import javax.jcr.ValueFactory; +import javax.jcr.Workspace; +import javax.jcr.lock.Lock; +import javax.jcr.lock.LockException; +import javax.jcr.nodetype.ConstraintViolationException; +import javax.jcr.nodetype.NoSuchNodeTypeException; +import javax.jcr.query.QueryResult; +import javax.jcr.query.Row; +import javax.jcr.query.RowIterator; +import javax.jcr.retention.RetentionManager; +import javax.jcr.security.AccessControlManager; +import javax.jcr.version.VersionException; + +import org.apache.jackrabbit.api.security.JackrabbitAccessControlManager; +import org.apache.jackrabbit.commons.iterator.NodeIteratorAdapter; +import org.apache.jackrabbit.oak.commons.PathUtils; +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; + +public class ProxySession<T extends Session> implements Session { + private final ProxyRepository repository; + public final T jcr; + protected final Session mount; + private final Set<String> mountPoints; + + public ProxySession(ProxyRepository repository, T jcr, Session mount, Set<String> mountPoints) { + this.repository = repository; + this.jcr = jcr; + this.mount = mount; + this.mountPoints = mountPoints; + } + + boolean isMount(String path) { + return path != null && (mountPoints.contains(path) || mountPoints.stream().anyMatch(mountPoint -> path.startsWith(mountPoint + "/"))); + } + + boolean isMountParent(String path) { + return mountPoints.stream().anyMatch(mountPoint -> mountPoint.startsWith((path + "/").replace("//", "/"))); + } + + boolean isMountDirectParent(String path) { + return mountPoints.stream().anyMatch(mountPoint -> PathUtils.getParentPath(mountPoint).equals(path)); + } + + public <F> F wrap(F source) { + if (source instanceof ProxyWrapper) { + return source; + } + return (F) (source instanceof Node ? new ProxyNode(this, (Node) source) : + source instanceof Property ? new ProxyProperty(this, (Property) source) : + source instanceof Item ? new ProxyItem<>(this, (Item) source) : + source instanceof Lock ? new ProxyLock(this, (Lock) source) : + source instanceof QueryResult ? new ProxyQueryResult(this, (QueryResult) source) : + source); + } + + public <F> F unwrap(F source) { + return (F) (source instanceof ProxyWrapper ? ((ProxyWrapper) source).delegate : source); + } + + public NodeIterator wrap(final NodeIterator iter) { + return new NodeIteratorAdapter(new Iterator<Node>() { + @Override + public boolean hasNext() { + return iter.hasNext(); + } + + @Override + public Node next() { + return wrap(iter.nextNode()); + } + + @Override + public void remove() { + iter.remove(); + } + }); + } + + public PropertyIterator wrap(final PropertyIterator iter) { + return new PropertyIterator() { + @Override + public Property nextProperty() { + return wrap(iter.nextProperty()); + } + + @Override + public void skip(long skipNum) { + iter.skip(skipNum); + } + + @Override + public long getSize() { + return iter.getSize(); + } + + @Override + public long getPosition() { + return iter.getPosition(); + } + + @Override + public boolean hasNext() { + return iter.hasNext(); + } + + @Override + public void remove() { + iter.remove(); + } + + @Override + public Object next() { + return wrap(iter.next()); + } + }; + } + + public RowIterator wrap(final RowIterator iter) { + return new RowIterator() { + + @Override + public Row nextRow() { + final Row row = iter.nextRow(); + + return new Row() { + @Override + public Value[] getValues() throws RepositoryException { + return row.getValues(); + } + + @Override + public Value getValue(String s) throws ItemNotFoundException, RepositoryException { + return row.getValue(s); + } + + @Override + public Node getNode() throws RepositoryException { + return wrap(row.getNode()); + } + + @Override + public Node getNode(String s) throws RepositoryException { + return wrap(row.getNode(s)); + } + + @Override + public String getPath() throws RepositoryException { + return row.getPath(); + } + + @Override + public String getPath(String s) throws RepositoryException { + return row.getPath(s); + } + + @Override + public double getScore() throws RepositoryException { + return row.getScore(); + } + + @Override + public double getScore(String s) throws RepositoryException { + return row.getScore(s); + } + }; + } + + @Override + public void skip(long l) { + iter.skip(l); + } + + @Override + public long getSize() { + return iter.getSize(); + } + + @Override + public long getPosition() { + return iter.getPosition(); + } + + @Override + public boolean hasNext() { + return iter.hasNext(); + } + + @Override + public Object next() { + return nextRow(); + } + + @Override + public void remove() { + iter.remove(); + } + }; + } + + @Override + public Repository getRepository() { + return this.repository; + } + + @Override + public String getUserID() { + return this.jcr.getUserID(); + } + + @Override + public String[] getAttributeNames() { + return this.jcr.getAttributeNames(); + } + + @Override + public Object getAttribute(String name) { + return this.jcr.getAttribute(name); + } + + @Override + public Node getRootNode() throws RepositoryException { + return wrap(this.jcr.getRootNode()); + } + + public NodeIterator getNodes(String path, NodeIterator childs) throws RepositoryException { + if (isMountDirectParent(path)) { + List<Node> buffer = new ArrayList<>(); + while (childs.hasNext()) { + Node child = childs.nextNode(); + if (!isMount(child.getPath())) { + buffer.add(child); + } + } + for (String mountPoint : this.mountPoints) { + if (PathUtils.getParentPath(mountPoint).equals(path)) { + buffer.add(this.mount.getNode(mountPoint)); + } + } + childs = new NodeIteratorAdapter(buffer); + } + return wrap(childs); + } + + public boolean hasNodes(Node node) throws RepositoryException { + return isMountDirectParent(node.getPath()) || node.hasNodes(); + } + + @Override + public Session impersonate(Credentials credentials) throws LoginException, RepositoryException { + return this.repository.impersonate(credentials, this.jcr, this.mount); + } + + @Override + public Node getNodeByUUID(String uuid) throws ItemNotFoundException, RepositoryException { + try { + return wrap(this.jcr.getNodeByUUID(uuid)); + } catch (RepositoryException ex) { + try { + return wrap(this.mount.getNodeByUUID(uuid)); + } catch (RepositoryException ignore) { + throw ex; + } + } + } + + @Override + public Node getNodeByIdentifier(String id) throws ItemNotFoundException, RepositoryException { + try { + return wrap(this.jcr.getNodeByIdentifier(id)); + } catch (RepositoryException ex) { + try { + return wrap(this.mount.getNodeByIdentifier(id)); + } catch (RepositoryException ignore) { + throw ex; + } + } + } + + @Override + public Item getItem(String absPath) throws PathNotFoundException, RepositoryException { + return wrap(isMount(absPath) ? this.mount.getItem(absPath) : this.jcr.getItem(absPath)); + } + + @Override + public Node getNode(String absPath) throws PathNotFoundException, RepositoryException { + return wrap(isMount(absPath) ? this.mount.getNode(absPath) : this.jcr.getNode(absPath)); + } + + @Override + public Property getProperty(String absPath) throws PathNotFoundException, RepositoryException { + return wrap(isMount(absPath) ? this.mount.getProperty(absPath) : this.jcr.getProperty(absPath)); + } + + @Override + public boolean itemExists(String absPath) throws RepositoryException { + return isMount(absPath) ? this.mount.itemExists(absPath) : this.jcr.itemExists(absPath); + } + + @Override + public boolean nodeExists(String absPath) throws RepositoryException { + return isMount(absPath) ? this.mount.nodeExists(absPath) : this.jcr.nodeExists(absPath); + } + + @Override + public boolean propertyExists(String absPath) throws RepositoryException { + return isMount(absPath) ? this.mount.propertyExists(absPath) : this.jcr.propertyExists(absPath); + } + + @Override + public void removeItem(String absPath) throws VersionException, LockException, ConstraintViolationException, AccessDeniedException, RepositoryException { + if (sync != null) { + sync.remove(absPath); + } + if (isMount(absPath)) { + this.mount.removeItem(absPath); + } else { + this.jcr.removeItem(absPath); + if (isMountParent(absPath)) { + for (String mountPoint : this.mountPoints) { + if (mountPoint.startsWith((absPath + "/").replace("//", "/"))) { + for (NodeIterator iter = this.mount.getNode(mountPoint).getNodes(); iter.hasNext(); ) { + iter.nextNode().remove(); + } + } + } + } + } + } + + private volatile Set<String> sync; + + private final static List<String> ignore = Arrays.asList("jcr:primaryType", "jcr:created", "jcr:createdBy"); + + @Override + public void save() throws AccessDeniedException, ItemExistsException, ReferentialIntegrityException, ConstraintViolationException, InvalidItemStateException, VersionException, LockException, NoSuchNodeTypeException, RepositoryException { + if (sync != null) { + for (String path : sync) { + if (this.jcr.nodeExists(path)) { + Node jcrNode = jcr.getNode(path); + Node mountNode = mount.nodeExists(path) ? + mount.getNode(path) : + mount.getNode(PathUtils.getParentPath(path)).addNode(PathUtils.getName(path), jcrNode.getPrimaryNodeType().getName()); + for (PropertyIterator iter = jcrNode.getProperties(); iter.hasNext(); ) { + Property property = iter.nextProperty(); + try { + if (property.isMultiple()) { + mountNode.setProperty(property.getName(), property.getValues()); + } else { + mountNode.setProperty(property.getName(), property.getValue()); + } + } catch (ConstraintViolationException ex) { + } + } + } + } + sync = null; + } + + this.jcr.save(); + + this.mount.save(); + } + + @Override + public void refresh(boolean keepChanges) throws RepositoryException { + sync = null; + this.jcr.refresh(keepChanges); + this.mount.refresh(keepChanges); + } + + public void refresh(String path, Item item, boolean keepChanges) throws RepositoryException { + sync = null; + item.refresh(keepChanges); + if (!isMount(path) && isMountParent(path)) { + this.mount.getRootNode().refresh(keepChanges); + } + } + + @Override + public boolean hasPendingChanges() throws RepositoryException { + return this.jcr.hasPendingChanges() || this.mount.hasPendingChanges(); + } + + @Override + public ValueFactory getValueFactory() throws UnsupportedRepositoryOperationException, RepositoryException { + return this.jcr.getValueFactory(); + } + + @Override + public boolean hasPermission(String absPath, String actions) throws RepositoryException { + return isMount(absPath) ? true : this.jcr.hasPermission(absPath, actions); + } + + @Override + public void checkPermission(String absPath, String actions) throws AccessControlException, RepositoryException { + if (!isMount(absPath)) { + this.jcr.checkPermission(absPath, actions); + } + } + + @Override + public boolean hasCapability(String methodName, Object target, Object[] arguments) throws RepositoryException { + return this.jcr.hasCapability(methodName, target, arguments); + } + + @Override + public ContentHandler getImportContentHandler(String parentAbsPath, int uuidBehavior) throws PathNotFoundException, ConstraintViolationException, VersionException, LockException, RepositoryException { + if (isMount(parentAbsPath)) { + return this.mount.getImportContentHandler(parentAbsPath, uuidBehavior); + } else { + return this.jcr.getImportContentHandler(parentAbsPath, uuidBehavior); + } + } + + @Override + public void importXML(String parentAbsPath, InputStream in, int uuidBehavior) throws IOException, PathNotFoundException, ItemExistsException, ConstraintViolationException, VersionException, InvalidSerializedDataException, LockException, RepositoryException { + if (isMount(parentAbsPath)) { + this.mount.importXML(parentAbsPath, in, uuidBehavior); + } else { + this.jcr.importXML(parentAbsPath, in, uuidBehavior); + } + } + + @Override + public void exportSystemView(String absPath, ContentHandler contentHandler, boolean skipBinary, boolean noRecurse) throws PathNotFoundException, SAXException, RepositoryException { + if (isMount(absPath)) { + this.mount.exportSystemView(absPath, contentHandler, skipBinary, noRecurse); + } else { + this.jcr.exportSystemView(absPath, contentHandler, skipBinary, noRecurse); + } + } + + @Override + public void exportSystemView(String absPath, OutputStream out, boolean skipBinary, boolean noRecurse) throws IOException, PathNotFoundException, RepositoryException { + if (isMount(absPath)) { + this.mount.exportSystemView(absPath, out, skipBinary, noRecurse); + } else { + this.jcr.exportSystemView(absPath, out, skipBinary, noRecurse); + } + } + + @Override + public void exportDocumentView(String absPath, ContentHandler contentHandler, boolean skipBinary, boolean noRecurse) throws PathNotFoundException, SAXException, RepositoryException { + if (isMount(absPath)) { + this.mount.exportDocumentView(absPath, contentHandler, skipBinary, noRecurse); + } else { + this.jcr.exportDocumentView(absPath, contentHandler, skipBinary, noRecurse); + } + } + + @Override + public void exportDocumentView(String absPath, OutputStream out, boolean skipBinary, boolean noRecurse) throws IOException, PathNotFoundException, RepositoryException { + if (isMount(absPath)) { + this.mount.exportDocumentView(absPath, out, skipBinary, noRecurse); + } else { + this.jcr.exportDocumentView(absPath, out, skipBinary, noRecurse); + } + } + + @Override + public void setNamespacePrefix(String prefix, String uri) throws NamespaceException, RepositoryException { + this.jcr.setNamespacePrefix(prefix, uri); + this.mount.setNamespacePrefix(prefix, uri); + } + + @Override + public String[] getNamespacePrefixes() throws RepositoryException { + return this.jcr.getNamespacePrefixes(); + } + + @Override + public String getNamespaceURI(String prefix) throws NamespaceException, RepositoryException { + return this.jcr.getNamespaceURI(prefix); + } + + @Override + public String getNamespacePrefix(String uri) throws NamespaceException, RepositoryException { + return this.jcr.getNamespacePrefix(uri); + } + + @Override + public void logout() { + this.jcr.logout(); + this.mount.logout(); + } + + @Override + public boolean isLive() { + return this.jcr.isLive(); + } + + @Override + public void addLockToken(String lt) { + this.jcr.addLockToken(lt); + } + + @Override + public String[] getLockTokens() { + return this.jcr.getLockTokens(); + } + + @Override + public void removeLockToken(String lt) { + this.jcr.removeLockToken(lt); + } + + @Override + public AccessControlManager getAccessControlManager() throws UnsupportedRepositoryOperationException, RepositoryException { + AccessControlManager manager = this.jcr.getAccessControlManager(); + return manager instanceof JackrabbitAccessControlManager ? + new ProxyJackrabbitAccessControlManager(this, (JackrabbitAccessControlManager) manager, (JackrabbitAccessControlManager) this.mount.getAccessControlManager()) : + new ProxyAccessControlManager<>(this, manager, this.mount.getAccessControlManager()); + } + + @Override + public RetentionManager getRetentionManager() throws UnsupportedRepositoryOperationException, RepositoryException { + return this.jcr.getRetentionManager(); + } + + @Override + public void move(String srcAbsPath, String destAbsPath) throws ItemExistsException, PathNotFoundException, VersionException, ConstraintViolationException, LockException, RepositoryException { + if (isMount(srcAbsPath) && isMount(destAbsPath)) { + this.mount.move(srcAbsPath, destAbsPath); + } else if (!isMount(srcAbsPath) && !isMount(destAbsPath)) { + this.jcr.move(srcAbsPath, destAbsPath); + } else { + throw new IllegalStateException("Move between jcr and mount not supported"); + } + } + + @Override + public Workspace getWorkspace() { + return new ProxyWorkspace(this, this.jcr.getWorkspace(), this.mount.getWorkspace()); + } + + public Node addNode(String parent, String path, String name) throws RepositoryException { + if (isMount(path)) { + return wrap(this.mount.getNode(parent).addNode(name)); + } + if (isMountParent(path)) { + this.mount.getNode(parent).addNode(name); + if (sync == null) { + sync = new HashSet<>(); + } + sync.add(path); + } + return wrap(this.jcr.getNode(parent).addNode(name)); + } + + public Node addNode(String parent, String path, String name, String type) throws RepositoryException { + if (isMount(path)) { + return wrap(this.mount.getNode(parent).addNode(name, type)); + } + if (isMountParent(path)) { + this.mount.getNode(parent).addNode(name, type); + if (sync == null) { + sync = new HashSet<>(); + } + sync.add(path); + } + return wrap(this.jcr.getNode(parent).addNode(name, type)); + } +} diff --git a/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyUserManager.java b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyUserManager.java new file mode 100644 index 0000000..7755789 --- /dev/null +++ b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyUserManager.java @@ -0,0 +1,123 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sling.jcr.base.internal.mount; + +import java.security.Principal; +import java.util.Iterator; + +import javax.jcr.RepositoryException; +import javax.jcr.UnsupportedRepositoryOperationException; + +import org.apache.jackrabbit.api.JackrabbitSession; +import org.apache.jackrabbit.api.security.user.Authorizable; +import org.apache.jackrabbit.api.security.user.AuthorizableExistsException; +import org.apache.jackrabbit.api.security.user.AuthorizableTypeException; +import org.apache.jackrabbit.api.security.user.Group; +import org.apache.jackrabbit.api.security.user.Query; +import org.apache.jackrabbit.api.security.user.User; +import org.apache.jackrabbit.api.security.user.UserManager; + +public class ProxyUserManager extends ProxyWrapper<UserManager> implements UserManager { + private final UserManager mount; + + public ProxyUserManager(ProxySession<JackrabbitSession> mountSession, UserManager delegate, UserManager mount) { + super(mountSession, delegate); + this.mount = mount; + } + + + public Authorizable getAuthorizable(String id) throws RepositoryException { + return delegate.getAuthorizable(id); + } + + public <T extends Authorizable> T getAuthorizable(String id, Class<T> authorizableClass) throws AuthorizableTypeException, RepositoryException { + return delegate.getAuthorizable(id, authorizableClass); + } + + public Authorizable getAuthorizable(Principal principal) throws RepositoryException { + return delegate.getAuthorizable(principal); + } + + public Authorizable getAuthorizableByPath(String path) throws UnsupportedRepositoryOperationException, RepositoryException { + return delegate.getAuthorizableByPath(path); + } + + public Iterator<Authorizable> findAuthorizables(String relPath, String value) throws RepositoryException { + return delegate.findAuthorizables(relPath, value); + } + + public Iterator<Authorizable> findAuthorizables(String relPath, String value, int searchType) throws RepositoryException { + return delegate.findAuthorizables(relPath, value, searchType); + } + + public Iterator<Authorizable> findAuthorizables(Query query) throws RepositoryException { + return delegate.findAuthorizables(query); + } + + public User createUser(String userID, String password) throws AuthorizableExistsException, RepositoryException { + User user = delegate.createUser(userID, password); + mount.createUser(userID, password, user.getPrincipal(), user.getPath()); + return user; + } + + public User createUser(String userID, String password, Principal principal, String intermediatePath) throws AuthorizableExistsException, RepositoryException { + User user = delegate.createUser(userID, password, principal, intermediatePath); + mount.createUser(userID, password, principal, user.getPath()); + return user; + } + + public User createSystemUser(String userID, String intermediatePath) throws AuthorizableExistsException, RepositoryException { + User user = delegate.createSystemUser(userID, intermediatePath); + mount.createSystemUser(userID, user.getPath()); + return user; + } + + public Group createGroup(String groupID) throws AuthorizableExistsException, RepositoryException { + Group group = delegate.createGroup(groupID); + mount.createGroup(groupID, group.getPrincipal(), group.getPath()); + return group; + } + + public Group createGroup(Principal principal) throws AuthorizableExistsException, RepositoryException { + Group group = delegate.createGroup(principal); + mount.createGroup(group.getID(), principal, group.getPath()); + return group; + } + + public Group createGroup(Principal principal, String intermediatePath) throws AuthorizableExistsException, RepositoryException { + Group group = delegate.createGroup(principal, intermediatePath); + mount.createGroup(principal, group.getPath()); + return group; + } + + public Group createGroup(String groupID, Principal principal, String intermediatePath) throws AuthorizableExistsException, RepositoryException { + Group group = delegate.createGroup(groupID, principal, intermediatePath); + mount.createGroup(groupID, principal, group.getPath()); + return group; + } + + public boolean isAutoSave() { + return delegate.isAutoSave(); + } + + public void autoSave(boolean enable) throws UnsupportedRepositoryOperationException, RepositoryException { + delegate.autoSave(enable); + mount.autoSave(enable); + } +} diff --git a/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyWorkspace.java b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyWorkspace.java new file mode 100644 index 0000000..75c1fb4 --- /dev/null +++ b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyWorkspace.java @@ -0,0 +1,168 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sling.jcr.base.internal.mount; + +import java.io.IOException; +import java.io.InputStream; + +import javax.jcr.AccessDeniedException; +import javax.jcr.InvalidItemStateException; +import javax.jcr.InvalidSerializedDataException; +import javax.jcr.ItemExistsException; +import javax.jcr.NamespaceRegistry; +import javax.jcr.NoSuchWorkspaceException; +import javax.jcr.PathNotFoundException; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.UnsupportedRepositoryOperationException; +import javax.jcr.Workspace; +import javax.jcr.lock.LockException; +import javax.jcr.lock.LockManager; +import javax.jcr.nodetype.ConstraintViolationException; +import javax.jcr.nodetype.NodeTypeManager; +import javax.jcr.observation.ObservationManager; +import javax.jcr.query.QueryManager; +import javax.jcr.version.Version; +import javax.jcr.version.VersionException; +import javax.jcr.version.VersionManager; + +import org.xml.sax.ContentHandler; + +public class ProxyWorkspace<T extends Workspace> extends ProxyWrapper<T> implements Workspace { + final T delegate2; + + public ProxyWorkspace(ProxySession mountSession, T delegate, T delegate2) { + super(mountSession, delegate); + this.delegate2 = delegate2; + } + + @Override + public Session getSession() { + return this.mountSession; + } + + @Override + public String getName() { + return delegate.getName(); + } + + @Override + public QueryManager getQueryManager() throws RepositoryException { + return new ProxyQueryManager(this.mountSession, delegate.getQueryManager(), this.delegate2.getQueryManager()); + } + + // TODO: revisit the below + + @Override + public ContentHandler getImportContentHandler(String parentAbsPath, int uuidBehavior) throws PathNotFoundException, ConstraintViolationException, VersionException, LockException, AccessDeniedException, RepositoryException { + return this.mountSession.getImportContentHandler(parentAbsPath, uuidBehavior); + } + + @Override + public void importXML(String parentAbsPath, InputStream in, int uuidBehavior) throws IOException, VersionException, PathNotFoundException, ItemExistsException, ConstraintViolationException, InvalidSerializedDataException, LockException, AccessDeniedException, RepositoryException { + this.mountSession.importXML(parentAbsPath, in, uuidBehavior); + } + + @Override + public void copy(String srcAbsPath, String destAbsPath) throws ConstraintViolationException, VersionException, AccessDeniedException, PathNotFoundException, ItemExistsException, LockException, RepositoryException { + if (mountSession.isMount(srcAbsPath) && mountSession.isMount(destAbsPath)) { + delegate2.copy(srcAbsPath, destAbsPath); + } else { + delegate.copy(srcAbsPath, destAbsPath); + } + } + + @Override + public void copy(String srcWorkspace, String srcAbsPath, String destAbsPath) throws NoSuchWorkspaceException, ConstraintViolationException, VersionException, AccessDeniedException, PathNotFoundException, ItemExistsException, LockException, RepositoryException { + if (mountSession.isMount(srcAbsPath) && mountSession.isMount(destAbsPath)) { + delegate2.copy(srcWorkspace, srcAbsPath, destAbsPath); + } else { + delegate.copy(srcWorkspace, srcAbsPath, destAbsPath); + } + } + + @Override + public void clone(String srcWorkspace, String srcAbsPath, String destAbsPath, boolean removeExisting) throws NoSuchWorkspaceException, ConstraintViolationException, VersionException, AccessDeniedException, PathNotFoundException, ItemExistsException, LockException, RepositoryException { + if (mountSession.isMount(srcAbsPath) && mountSession.isMount(destAbsPath)) { + delegate2.clone(srcWorkspace, srcAbsPath, destAbsPath, removeExisting); + } else { + delegate.clone(srcWorkspace, srcAbsPath, destAbsPath, removeExisting); + } + } + + @Override + public void move(String srcAbsPath, String destAbsPath) throws ConstraintViolationException, VersionException, AccessDeniedException, PathNotFoundException, ItemExistsException, LockException, RepositoryException { + if (mountSession.isMount(srcAbsPath) && mountSession.isMount(destAbsPath)) { + delegate2.move(srcAbsPath, destAbsPath); + } else { + delegate.move(srcAbsPath, destAbsPath); + } + } + + @Override + public void restore(Version[] versions, boolean removeExisting) throws ItemExistsException, UnsupportedRepositoryOperationException, VersionException, LockException, InvalidItemStateException, RepositoryException { + delegate.restore(versions, removeExisting); + } + + @Override + public void createWorkspace(String name) throws AccessDeniedException, UnsupportedRepositoryOperationException, RepositoryException { + delegate.createWorkspace(name); + } + + @Override + public void createWorkspace(String name, String srcWorkspace) throws AccessDeniedException, UnsupportedRepositoryOperationException, NoSuchWorkspaceException, RepositoryException { + delegate.createWorkspace(name, srcWorkspace); + } + + @Override + public void deleteWorkspace(String name) throws AccessDeniedException, UnsupportedRepositoryOperationException, NoSuchWorkspaceException, RepositoryException { + delegate.deleteWorkspace(name); + } + + + @Override + public LockManager getLockManager() throws UnsupportedRepositoryOperationException, RepositoryException { + return delegate.getLockManager(); + } + + @Override + public NamespaceRegistry getNamespaceRegistry() throws RepositoryException { + return new ProxyNamespaceRegistry(delegate.getNamespaceRegistry(), this.delegate2.getNamespaceRegistry()); + } + + @Override + public NodeTypeManager getNodeTypeManager() throws RepositoryException { + return new ProxyNodeTypeManager(delegate.getNodeTypeManager(), this.delegate2.getNodeTypeManager()); + } + + @Override + public ObservationManager getObservationManager() throws UnsupportedRepositoryOperationException, RepositoryException { + return delegate.getObservationManager(); + } + + @Override + public VersionManager getVersionManager() throws UnsupportedRepositoryOperationException, RepositoryException { + return delegate.getVersionManager(); + } + + @Override + public String[] getAccessibleWorkspaceNames() throws RepositoryException { + return delegate.getAccessibleWorkspaceNames(); + } +} diff --git a/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyWrapper.java b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyWrapper.java new file mode 100644 index 0000000..2de05ee --- /dev/null +++ b/src/main/java/org/apache/sling/jcr/base/internal/mount/ProxyWrapper.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sling.jcr.base.internal.mount; + +import org.apache.jackrabbit.oak.commons.PathUtils; + +public class ProxyWrapper<T> { + final ProxySession<?> mountSession; + final T delegate; + + public ProxyWrapper(ProxySession<?> mountSession, T delegate) { + this.mountSession = mountSession; + this.delegate = delegate; + } + + String concat(String parent, String relPath) { + if (relPath != null) { + while (relPath.startsWith("/")) { + relPath = relPath.substring(1); + } + } + return PathUtils.concat(parent, relPath); + } +} diff --git a/src/main/java/org/apache/sling/jcr/base/spi/RepositoryMount.java b/src/main/java/org/apache/sling/jcr/base/spi/RepositoryMount.java new file mode 100644 index 0000000..f009877 --- /dev/null +++ b/src/main/java/org/apache/sling/jcr/base/spi/RepositoryMount.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sling.jcr.base.spi; + +import org.apache.jackrabbit.api.JackrabbitRepository; + +public interface RepositoryMount extends JackrabbitRepository +{ + String PARENT_SESSION_KEY = "org.apache.sling.jcr.base.RepositoryMount.PARENT_SESSION"; + String MOUNT_POINTS_KEY = "org.apache.sling.jcr.base.RepositoryMount.MOUNT_POINTS"; +} diff --git a/src/main/java/org/apache/sling/jcr/base/spi/package-info.java b/src/main/java/org/apache/sling/jcr/base/spi/package-info.java new file mode 100644 index 0000000..a34c77c --- /dev/null +++ b/src/main/java/org/apache/sling/jcr/base/spi/package-info.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * The {@code org.apache.sling.jcr.base.spi} package provides a + * way to bifurcate requests to subpaths to a mount provider. + */ [email protected]("0.1.0") +package org.apache.sling.jcr.base.spi; + +
