You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ol...@apache.org on 2016/08/12 11:02:39 UTC

svn commit: r1756146 - in /sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling: jcr/ jcr/oak/ jcr/oak/server/ oak/

Author: olli
Date: Fri Aug 12 11:02:39 2016
New Revision: 1756146

URL: http://svn.apache.org/viewvc?rev=1756146&view=rev
Log:
Move package oak into org.apache.sling.jcr

Added:
    sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/
    sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/
    sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/
    sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/OakSlingRepository.java
    sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/OakSlingRepositoryManager.java
    sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/OakSlingRepositoryManagerConfiguration.java
    sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/TCCLWrappingJackrabbitRepository.java
    sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/TCCLWrappingJackrabbitSession.java
    sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/package-info.java
Removed:
    sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/oak/

Added: sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/OakSlingRepository.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/OakSlingRepository.java?rev=1756146&view=auto
==============================================================================
--- sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/OakSlingRepository.java (added)
+++ sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/OakSlingRepository.java Fri Aug 12 11:02:39 2016
@@ -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 SF 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.oak.server;
+
+import java.security.Principal;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.security.auth.Subject;
+
+import org.apache.jackrabbit.api.JackrabbitRepository;
+import org.apache.jackrabbit.oak.api.AuthInfo;
+import org.apache.jackrabbit.oak.spi.security.authentication.AuthInfoImpl;
+import org.apache.jackrabbit.oak.spi.security.principal.AdminPrincipal;
+import org.apache.sling.jcr.base.AbstractSlingRepository2;
+import org.apache.sling.jcr.base.AbstractSlingRepositoryManager;
+import org.osgi.framework.Bundle;
+
+import static java.util.Collections.singleton;
+
+/**
+ * A Sling repository implementation that wraps the Oak OSGi repository
+ * implementation from the Oak project.
+ */
+public class OakSlingRepository extends AbstractSlingRepository2 {
+
+    private final String adminId;
+
+    protected OakSlingRepository(final AbstractSlingRepositoryManager manager, final Bundle usingBundle, final String adminId) {
+        super(manager, usingBundle);
+        this.adminId = adminId;
+    }
+
+    @Override
+    protected Session createAdministrativeSession(String workspace) throws RepositoryException {
+        // TODO: use principal provider to retrieve admin principal
+        Set<? extends Principal> principals = singleton(new AdminPrincipal() {
+            @Override
+            public String getName() {
+                return OakSlingRepository.this.adminId;
+            }
+        });
+        AuthInfo authInfo = new AuthInfoImpl(this.adminId, Collections.<String, Object> emptyMap(), principals);
+        Subject subject = new Subject(true, principals, singleton(authInfo), Collections.<Object> emptySet());
+        Session adminSession;
+        try {
+            adminSession = Subject.doAsPrivileged(subject, new PrivilegedExceptionAction<Session>() {
+                @Override
+                public Session run() throws Exception {
+                    Map<String, Object> attrs = new HashMap<String, Object>();
+                    attrs.put("oak.refresh-interval", 0);
+                    // TODO OAK-803: Backwards compatibility of long-lived sessions
+                	JackrabbitRepository repo = (JackrabbitRepository) getRepository();
+                    return repo.login(null, null, attrs);
+                }
+            }, null);
+        } catch (PrivilegedActionException e) {
+            throw new RepositoryException("failed to retrieve admin session.", e);
+        }
+
+        return adminSession;
+    }
+
+}

Added: sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/OakSlingRepositoryManager.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/OakSlingRepositoryManager.java?rev=1756146&view=auto
==============================================================================
--- sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/OakSlingRepositoryManager.java (added)
+++ sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/OakSlingRepositoryManager.java Fri Aug 12 11:02:39 2016
@@ -0,0 +1,327 @@
+/*
+ * 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 SF 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.oak.server;
+
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.concurrent.Executor;
+
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.security.Privilege;
+
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.api.JackrabbitRepository;
+import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
+import org.apache.jackrabbit.oak.Oak;
+import org.apache.jackrabbit.oak.jcr.Jcr;
+import org.apache.jackrabbit.oak.osgi.OsgiWhiteboard;
+import org.apache.jackrabbit.oak.plugins.commit.ConflictValidatorProvider;
+import org.apache.jackrabbit.oak.plugins.commit.JcrConflictHandler;
+import org.apache.jackrabbit.oak.plugins.index.aggregate.NodeAggregator;
+import org.apache.jackrabbit.oak.plugins.index.aggregate.SimpleNodeAggregator;
+import org.apache.jackrabbit.oak.plugins.index.lucene.util.LuceneIndexHelper;
+import org.apache.jackrabbit.oak.plugins.name.NameValidatorProvider;
+import org.apache.jackrabbit.oak.plugins.name.NamespaceEditorProvider;
+import org.apache.jackrabbit.oak.plugins.nodetype.TypeEditorProvider;
+import org.apache.jackrabbit.oak.plugins.nodetype.write.InitialContent;
+import org.apache.jackrabbit.oak.plugins.observation.CommitRateLimiter;
+import org.apache.jackrabbit.oak.plugins.version.VersionHook;
+import org.apache.jackrabbit.oak.spi.lifecycle.RepositoryInitializer;
+import org.apache.jackrabbit.oak.spi.security.SecurityProvider;
+import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal;
+import org.apache.jackrabbit.oak.spi.security.user.UserConfiguration;
+import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard;
+import org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardIndexEditorProvider;
+import org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardIndexProvider;
+import org.apache.sling.commons.threads.ThreadPool;
+import org.apache.sling.commons.threads.ThreadPoolManager;
+import org.apache.sling.jcr.api.SlingRepository;
+import org.apache.sling.jcr.base.AbstractSlingRepository2;
+import org.apache.sling.jcr.base.AbstractSlingRepositoryManager;
+import org.apache.sling.serviceusermapping.ServiceUserMapper;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferencePolicy;
+import org.osgi.service.component.annotations.ReferencePolicyOption;
+import org.osgi.service.metatype.annotations.Designate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static com.google.common.collect.ImmutableSet.of;
+import static java.util.Collections.singleton;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME;
+import static org.apache.jackrabbit.oak.plugins.index.IndexUtils.createIndexDefinition;
+
+/**
+ * A Sling repository implementation that wraps the Oak repository
+ * implementation from the Jackrabbit Oak project.
+ */
+@Component(
+    immediate = true
+)
+@Designate(
+    ocd = OakSlingRepositoryManagerConfiguration.class
+)
+public class OakSlingRepositoryManager extends AbstractSlingRepositoryManager {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    @Reference
+    private ServiceUserMapper serviceUserMapper;
+
+    @Reference
+    private NodeStore nodeStore;
+
+    private ComponentContext componentContext;
+
+    @Reference
+    private ThreadPoolManager threadPoolManager = null;
+
+    private ThreadPool threadPool;
+
+    private ServiceRegistration oakExecutorServiceReference;
+
+    private final WhiteboardIndexProvider indexProvider = new WhiteboardIndexProvider();
+
+    private final WhiteboardIndexEditorProvider indexEditorProvider = new WhiteboardIndexEditorProvider();
+
+    private CommitRateLimiter commitRateLimiter;
+
+    private OakSlingRepositoryManagerConfiguration configuration;
+
+    @Reference(
+        policy = ReferencePolicy.STATIC,
+        policyOption = ReferencePolicyOption.GREEDY
+    )
+    private SecurityProvider securityProvider = null;
+
+    private ServiceRegistration nodeAggregatorRegistration;
+
+    public OakSlingRepositoryManager() {
+    }
+
+    @Override
+    protected ServiceUserMapper getServiceUserMapper() {
+        return this.serviceUserMapper;
+    }
+
+    @Override
+    protected Repository acquireRepository() {
+        final BundleContext bundleContext = componentContext.getBundleContext();
+        final Whiteboard whiteboard = new OsgiWhiteboard(bundleContext);
+        this.indexProvider.start(whiteboard);
+        this.indexEditorProvider.start(whiteboard);
+        this.oakExecutorServiceReference = bundleContext.registerService(
+                Executor.class.getName(), new Executor() {
+            @Override
+            public void execute(Runnable command) {
+                threadPool.execute(command);
+            }
+        }, new Hashtable<String, Object>());
+
+        final Oak oak = new Oak(nodeStore)
+            .withAsyncIndexing("async", 5);
+
+        final Jcr jcr = new Jcr(oak, false)
+        .with(new InitialContent())
+        .with(new ExtraSlingContent())
+
+        .with(JcrConflictHandler.createJcrConflictHandler())
+        .with(new VersionHook())
+
+        .with(securityProvider)
+
+        .with(new NameValidatorProvider())
+        .with(new NamespaceEditorProvider())
+        .with(new TypeEditorProvider())
+        .with(new ConflictValidatorProvider())
+
+        // index stuff
+        .with(indexProvider)
+        .with(indexEditorProvider)
+        .with(getDefaultWorkspace())
+        .with(whiteboard)
+        .withFastQueryResultSize(true)
+        .withObservationQueueLength(configuration.oak_observation_queue_length());
+
+        if (commitRateLimiter != null) {
+            jcr.with(commitRateLimiter);
+        }
+
+        jcr.createContentRepository();
+
+        return new TCCLWrappingJackrabbitRepository((JackrabbitRepository) jcr.createRepository());
+    }
+
+    private void setup(final SlingRepository repository) {
+        final boolean anonymous_read_all = configuration.anonymous_read_all();
+        if (anonymous_read_all) {
+            log.warn("anonymous.read.all is true, granting anonymous user read access on /");
+            Session session = null;
+            try {
+                // TODO do we need to go via PrivilegeManager for the names? See OAK-1016 example.
+                session = repository.loginAdministrative(getDefaultWorkspace());
+                final String[] privileges = new String[]{Privilege.JCR_READ};
+                AccessControlUtils.addAccessControlEntry(
+                    session,
+                    "/",
+                    EveryonePrincipal.getInstance(),
+                    privileges,
+                    true);
+                session.save();
+            } catch (RepositoryException re) {
+                log.error("TODO: Failed setting up anonymous access", re);
+            } finally {
+                if (session != null) {
+                    session.logout();
+                }
+            }
+        } else {
+            log.warn("TODO: should disable anonymous access when anonymous.read.all becomes false");
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    protected Dictionary<String, Object> getServiceRegistrationProperties() {
+        return componentContext.getProperties();
+    }
+
+    @Override
+    protected AbstractSlingRepository2 create(Bundle usingBundle) {
+        final String adminId = getAdminId();
+        final AbstractSlingRepository2 slingRepository = new OakSlingRepository(this, usingBundle, adminId);
+        setup(slingRepository);
+        return slingRepository;
+    }
+
+    @Override
+    protected void destroy(AbstractSlingRepository2 repositoryServiceInstance) {
+        // nothing to do, just drop the reference
+    }
+
+    @Override
+    protected void disposeRepository(Repository repository) {
+        this.indexProvider.stop();
+        this.indexEditorProvider.stop();
+        this.oakExecutorServiceReference.unregister();
+        this.oakExecutorServiceReference = null;
+        ((JackrabbitRepository) repository).shutdown();
+    }
+
+    @Activate
+    private void activate(final OakSlingRepositoryManagerConfiguration configuration, final ComponentContext componentContext) {
+        this.configuration = configuration;
+        this.componentContext = componentContext;
+        final BundleContext bundleContext = componentContext.getBundleContext();
+
+        final String defaultWorkspace = configuration.defaultWorkspace();
+        final boolean disableLoginAdministrative = !configuration.admin_login_enabled();
+
+        if (configuration.oak_observation_limitCommitRate()) {
+            commitRateLimiter = new CommitRateLimiter();
+        }
+        this.threadPool = threadPoolManager.get("oak-observation");
+        this.nodeAggregatorRegistration = bundleContext.registerService(NodeAggregator.class.getName(), getNodeAggregator(), null);
+
+        super.start(bundleContext, defaultWorkspace, disableLoginAdministrative);
+    }
+
+    @Deactivate
+    private void deactivate() {
+        super.stop();
+        this.componentContext = null;
+        this.threadPoolManager.release(this.threadPool);
+        this.threadPool = null;
+        this.nodeAggregatorRegistration.unregister();
+    }
+
+    private String getAdminId() {
+        return securityProvider.getConfiguration(UserConfiguration.class).getParameters().getConfigValue(UserConstants.PARAM_ADMIN_ID, UserConstants.DEFAULT_ADMIN_ID);
+    }
+
+    private static NodeAggregator getNodeAggregator() {
+        return new SimpleNodeAggregator().newRuleWithName(JcrConstants.NT_FILE, Collections.singletonList(JcrConstants.JCR_CONTENT));
+    }
+
+    private static final class ExtraSlingContent implements RepositoryInitializer {
+
+
+        @Override
+        public void initialize(NodeBuilder root) {
+            if (root.hasChildNode(INDEX_DEFINITIONS_NAME)) {
+                NodeBuilder index = root.child(INDEX_DEFINITIONS_NAME);
+
+                // jcr:
+                property(index, "jcrLanguage", "jcr:language");
+                property(index, "jcrLockOwner", "jcr:lockOwner");
+
+                // sling:
+                property(index, "slingAlias", "sling:alias");
+                property(index, "slingResource", "sling:resource");
+                property(index, "slingResourceType", "sling:resourceType");
+                property(index, "slingVanityPath", "sling:vanityPath");
+
+                // various
+                property(index, "event.job.topic", "event.job.topic");
+                property(index, "slingeventEventId", "slingevent:eventId");
+                property(index, "extensionType", "extensionType");
+                property(index, "lockCreated", "lock.created");
+                property(index, "status", "status");
+                property(index, "type", "type");
+
+                // lucene full-text index
+                if (!index.hasChildNode("lucene")) {
+                    LuceneIndexHelper.newLuceneIndexDefinition(
+                            index, "lucene", LuceneIndexHelper.JR_PROPERTY_INCLUDES,
+                            of(
+                               "jcr:createdBy",
+                               "jcr:lastModifiedBy",
+                               "sling:alias",
+                               "sling:resourceType",
+                               "sling:vanityPath"),
+                            "async");
+                }
+
+            }
+        }
+
+        /**
+         * A convenience method to create a non-unique property index.
+         */
+        private static void property(NodeBuilder index, String indexName, String propertyName) {
+            if (!index.hasChildNode(indexName)) {
+                createIndexDefinition(index, indexName, true, false, singleton(propertyName), null);
+            }
+        }
+
+    }
+
+}

Added: sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/OakSlingRepositoryManagerConfiguration.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/OakSlingRepositoryManagerConfiguration.java?rev=1756146&view=auto
==============================================================================
--- sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/OakSlingRepositoryManagerConfiguration.java (added)
+++ sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/OakSlingRepositoryManagerConfiguration.java Fri Aug 12 11:02:39 2016
@@ -0,0 +1,74 @@
+/*
+ * 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 SF 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.oak.server;
+
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+
+@ObjectClassDefinition(
+    name = "Apache Sling JCR Oak Repository",
+    description = "Configuration to launch an embedded JCR Repository and provide it as a SlingRepository and a standard JCR Repository. In addition, if the registration URL is not empty, the repository is registered as defined."
+)
+@interface OakSlingRepositoryManagerConfiguration {
+
+    @AttributeDefinition(
+        name = "Repository Name",
+        description = "The name under which the repository will be registered in JNDI and RMI registries."
+    )
+    String name() default "oak-sling-repository";
+
+    @AttributeDefinition(
+        name = "Default Workspace",
+        description = "Name of the workspace to use by default if not is given in any of the login methods. This name is used "
+            + "to implement the SlingRepository.getDefaultWorkspace() "
+            + "method. If this name is empty, a null value is used in "
+            + "JCR calls so that the default workspace provided by the JCR repository is used."
+    )
+    String defaultWorkspace() default "default";
+
+    // For backwards compatibility loginAdministrative is still enabled
+    // In future releases, this default may change to false.
+    @AttributeDefinition(
+        name = "Enable Administrator Login",
+        description = "Whether to enable or disable the SlingRepository.loginAdministrative "
+            + "method. The default is 'true'. See "
+            + "http://sling.apache.org/documentation/the-sling-engine/service-authentication.html "
+            + "for information on deprecating and disabling the loginAdministrative method."
+    )
+    boolean admin_login_enabled() default true;
+
+    @AttributeDefinition(
+        name = "Allow anonymous reads",
+        description = "If true, the anonymous user has read access to the whole repository (for backwards compatibility)"
+    )
+    boolean anonymous_read_all() default true;
+
+    @AttributeDefinition(
+        name = "Observation queue length",
+        description = "Maximum number of pending revisions in a observation listener queue"
+    )
+    int oak_observation_queue_length() default 1000;
+
+    @AttributeDefinition(
+        name = "Commit rate limiter",
+        description = "Limit the commit rate once the number of pending revisions in the observation "
+            + "queue exceed 90% of its capacity."
+    )
+    boolean oak_observation_limitCommitRate() default false;
+
+}

Added: sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/TCCLWrappingJackrabbitRepository.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/TCCLWrappingJackrabbitRepository.java?rev=1756146&view=auto
==============================================================================
--- sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/TCCLWrappingJackrabbitRepository.java (added)
+++ sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/TCCLWrappingJackrabbitRepository.java Fri Aug 12 11:02:39 2016
@@ -0,0 +1,127 @@
+/*
+ * 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.oak.server;
+
+import java.util.Map;
+
+import javax.jcr.Credentials;
+import javax.jcr.LoginException;
+import javax.jcr.NoSuchWorkspaceException;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Value;
+
+import org.apache.jackrabbit.api.JackrabbitRepository;
+import org.apache.jackrabbit.api.JackrabbitSession;
+import org.apache.jackrabbit.oak.Oak;
+
+/**
+ * Custom <tt>JackrabbitRepository</tt> that ensures that the correct <tt>TCCL</tt> is set in OSGi environments
+ *
+ * <p>Oak still requires that for {@link JackrabbitRepository#login()} and
+ * {@link JackrabbitSession#impersonate(Credentials)} calls a custom thread context class loader is set. This wrapper
+ * simply ensures that the TCCL is set for all calls.</p>
+ */
+public class TCCLWrappingJackrabbitRepository implements JackrabbitRepository {
+
+    private final JackrabbitRepository wrapped;
+
+    public TCCLWrappingJackrabbitRepository(JackrabbitRepository wrapped) {
+        this.wrapped = wrapped;
+    }
+
+    // calls setting the TCCL
+
+    @Override
+    public Session login(Credentials credentials, String workspaceName)
+            throws LoginException, NoSuchWorkspaceException, RepositoryException {
+        return login(credentials, workspaceName, null);
+    }
+
+    @Override
+    public Session login(Credentials credentials) throws LoginException, RepositoryException {
+        return login(credentials, null, null);
+    }
+
+    @Override
+    public Session login(String workspaceName) throws LoginException, NoSuchWorkspaceException, RepositoryException {
+        return login(null, workspaceName, null);
+    }
+
+    @Override
+    public Session login() throws LoginException, RepositoryException {
+        return login(null, null);
+    }
+
+    @Override
+    public Session login(Credentials credentials, String workspaceName, Map<String, Object> attributes)
+            throws LoginException, NoSuchWorkspaceException, RepositoryException {
+
+        Thread thread = Thread.currentThread();
+
+        ClassLoader oldClassLoader = thread.getContextClassLoader();
+        thread.setContextClassLoader(Oak.class.getClassLoader());
+
+        try {
+            Session session = wrapped.login(credentials, workspaceName,attributes);
+            return new TCCLWrappingJackrabbitSession((JackrabbitSession) session);
+        } finally {
+            thread.setContextClassLoader(oldClassLoader);
+        }
+    }
+
+    // only pure delegate methods below
+
+    @Override
+    public String[] getDescriptorKeys() {
+        return wrapped.getDescriptorKeys();
+    }
+
+    @Override
+    public boolean isStandardDescriptor(String key) {
+        return wrapped.isStandardDescriptor(key);
+    }
+
+    @Override
+    public boolean isSingleValueDescriptor(String key) {
+        return wrapped.isSingleValueDescriptor(key);
+    }
+
+    @Override
+    public Value getDescriptorValue(String key) {
+        return wrapped.getDescriptorValue(key);
+    }
+
+    @Override
+    public Value[] getDescriptorValues(String key) {
+        return wrapped.getDescriptorValues(key);
+    }
+
+    @Override
+    public String getDescriptor(String key) {
+        return wrapped.getDescriptor(key);
+    }
+
+    @Override
+    public void shutdown() {
+        wrapped.shutdown();
+
+    }
+
+}

Added: sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/TCCLWrappingJackrabbitSession.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/TCCLWrappingJackrabbitSession.java?rev=1756146&view=auto
==============================================================================
--- sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/TCCLWrappingJackrabbitSession.java (added)
+++ sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/TCCLWrappingJackrabbitSession.java Fri Aug 12 11:02:39 2016
@@ -0,0 +1,340 @@
+/*
+ * 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.oak.server;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.AccessControlException;
+
+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.PathNotFoundException;
+import javax.jcr.Property;
+import javax.jcr.ReferentialIntegrityException;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.ValueFactory;
+import javax.jcr.Workspace;
+import javax.jcr.lock.LockException;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+import javax.jcr.retention.RetentionManager;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.version.VersionException;
+
+import org.apache.jackrabbit.api.JackrabbitSession;
+import org.apache.jackrabbit.api.security.principal.PrincipalManager;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.jackrabbit.oak.Oak;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+
+/**
+ * Custom <tt>JackrabbitSession</tt> that ensures that the correct <tt>TCCL</tt> is set in OSGi environments
+ *
+ *
+ * @see #TCCLWrappingJackrabbitSession(JackrabbitSession)
+ */
+public class TCCLWrappingJackrabbitSession implements JackrabbitSession {
+
+    private final JackrabbitSession wrapped;
+
+    public TCCLWrappingJackrabbitSession(JackrabbitSession wrapped) {
+        this.wrapped = wrapped;
+    }
+
+    // calls setting the TCCL
+
+    @Override
+    public Session impersonate(Credentials credentials) throws LoginException, RepositoryException {
+
+        Thread thread = Thread.currentThread();
+
+        ClassLoader oldClassLoader = thread.getContextClassLoader();
+        thread.setContextClassLoader(Oak.class.getClassLoader());
+
+        try {
+            Session session = wrapped.impersonate(credentials);
+            return new TCCLWrappingJackrabbitSession((JackrabbitSession) session);
+        } finally {
+            thread.setContextClassLoader(oldClassLoader);
+        }
+    }
+
+    // only pure delegate methods below
+
+    @Override
+    public Repository getRepository() {
+        return wrapped.getRepository();
+    }
+
+    @Override
+    public String getUserID() {
+        return wrapped.getUserID();
+    }
+
+    @Override
+    public String[] getAttributeNames() {
+        return wrapped.getAttributeNames();
+    }
+
+    @Override
+    public Object getAttribute(String name) {
+        return wrapped.getAttribute(name);
+    }
+
+    @Override
+    public boolean hasPermission(String absPath, String... actions) throws RepositoryException {
+        return wrapped.hasPermission(absPath, actions);
+    }
+
+    @Override
+    public Workspace getWorkspace() {
+        return wrapped.getWorkspace();
+    }
+
+    @Override
+    public Node getRootNode() throws RepositoryException {
+        return wrapped.getRootNode();
+    }
+
+    @Override
+    @SuppressWarnings("deprecation")
+    public Node getNodeByUUID(String uuid) throws ItemNotFoundException, RepositoryException {
+        return wrapped.getNodeByUUID(uuid);
+    }
+
+    @Override
+    public Node getNodeByIdentifier(String id) throws ItemNotFoundException, RepositoryException {
+        return wrapped.getNodeByIdentifier(id);
+    }
+
+    @Override
+    public Item getItem(String absPath) throws PathNotFoundException, RepositoryException {
+        return wrapped.getItem(absPath);
+    }
+
+    @Override
+    public PrincipalManager getPrincipalManager()
+            throws AccessDeniedException, UnsupportedRepositoryOperationException, RepositoryException {
+        return wrapped.getPrincipalManager();
+    }
+
+    @Override
+    public Node getNode(String absPath) throws PathNotFoundException, RepositoryException {
+        return wrapped.getNode(absPath);
+    }
+
+    @Override
+    public Property getProperty(String absPath) throws PathNotFoundException, RepositoryException {
+        return wrapped.getProperty(absPath);
+    }
+
+    @Override
+    public UserManager getUserManager()
+            throws AccessDeniedException, UnsupportedRepositoryOperationException, RepositoryException {
+        return wrapped.getUserManager();
+    }
+
+    @Override
+    public boolean itemExists(String absPath) throws RepositoryException {
+        return wrapped.itemExists(absPath);
+    }
+
+    @Override
+    public Item getItemOrNull(String absPath) throws RepositoryException {
+        return wrapped.getItemOrNull(absPath);
+    }
+
+    @Override
+    public boolean nodeExists(String absPath) throws RepositoryException {
+        return wrapped.nodeExists(absPath);
+    }
+
+    @Override
+    public Property getPropertyOrNull(String absPath) throws RepositoryException {
+        return wrapped.getPropertyOrNull(absPath);
+    }
+
+    @Override
+    public boolean propertyExists(String absPath) throws RepositoryException {
+        return wrapped.propertyExists(absPath);
+    }
+
+    @Override
+    public Node getNodeOrNull(String absPath) throws RepositoryException {
+        return wrapped.getNodeOrNull(absPath);
+    }
+
+    @Override
+    public void move(String srcAbsPath, String destAbsPath) throws ItemExistsException, PathNotFoundException,
+            VersionException, ConstraintViolationException, LockException, RepositoryException {
+        wrapped.move(srcAbsPath, destAbsPath);
+    }
+
+    @Override
+    public void removeItem(String absPath) throws VersionException, LockException, ConstraintViolationException,
+            AccessDeniedException, RepositoryException {
+        wrapped.removeItem(absPath);
+    }
+
+    @Override
+    public void save() throws AccessDeniedException, ItemExistsException, ReferentialIntegrityException,
+            ConstraintViolationException, InvalidItemStateException, VersionException, LockException,
+            NoSuchNodeTypeException, RepositoryException {
+        wrapped.save();
+    }
+
+    @Override
+    public void refresh(boolean keepChanges) throws RepositoryException {
+        wrapped.refresh(keepChanges);
+    }
+
+    @Override
+    public boolean hasPendingChanges() throws RepositoryException {
+        return wrapped.hasPendingChanges();
+    }
+
+    @Override
+    public ValueFactory getValueFactory() throws UnsupportedRepositoryOperationException, RepositoryException {
+        return wrapped.getValueFactory();
+    }
+
+    @Override
+    public boolean hasPermission(String absPath, String actions) throws RepositoryException {
+        return wrapped.hasPermission(absPath, actions);
+    }
+
+    @Override
+    public void checkPermission(String absPath, String actions) throws AccessControlException, RepositoryException {
+        wrapped.checkPermission(absPath, actions);
+    }
+
+    @Override
+    public boolean hasCapability(String methodName, Object target, Object[] arguments) throws RepositoryException {
+        return wrapped.hasCapability(methodName, target, arguments);
+    }
+
+    @Override
+    public ContentHandler getImportContentHandler(String parentAbsPath, int uuidBehavior) throws PathNotFoundException,
+            ConstraintViolationException, VersionException, LockException, RepositoryException {
+        return wrapped.getImportContentHandler(parentAbsPath, uuidBehavior);
+    }
+
+    @Override
+    public void importXML(String parentAbsPath, InputStream in, int uuidBehavior)
+            throws IOException, PathNotFoundException, ItemExistsException, ConstraintViolationException,
+            VersionException, InvalidSerializedDataException, LockException, RepositoryException {
+        wrapped.importXML(parentAbsPath, in, uuidBehavior);
+    }
+
+    @Override
+    public void exportSystemView(String absPath, ContentHandler contentHandler, boolean skipBinary, boolean noRecurse)
+            throws PathNotFoundException, SAXException, RepositoryException {
+        wrapped.exportSystemView(absPath, contentHandler, skipBinary, noRecurse);
+    }
+
+    @Override
+    public void exportSystemView(String absPath, OutputStream out, boolean skipBinary, boolean noRecurse)
+            throws IOException, PathNotFoundException, RepositoryException {
+        wrapped.exportSystemView(absPath, out, skipBinary, noRecurse);
+    }
+
+    @Override
+    public void exportDocumentView(String absPath, ContentHandler contentHandler, boolean skipBinary, boolean noRecurse)
+            throws PathNotFoundException, SAXException, RepositoryException {
+        wrapped.exportDocumentView(absPath, contentHandler, skipBinary, noRecurse);
+    }
+
+    @Override
+    public void exportDocumentView(String absPath, OutputStream out, boolean skipBinary, boolean noRecurse)
+            throws IOException, PathNotFoundException, RepositoryException {
+        wrapped.exportDocumentView(absPath, out, skipBinary, noRecurse);
+    }
+
+    @Override
+    public void setNamespacePrefix(String prefix, String uri) throws NamespaceException, RepositoryException {
+        wrapped.setNamespacePrefix(prefix, uri);
+    }
+
+    @Override
+    public String[] getNamespacePrefixes() throws RepositoryException {
+        return wrapped.getNamespacePrefixes();
+    }
+
+    @Override
+    public String getNamespaceURI(String prefix) throws NamespaceException, RepositoryException {
+        return wrapped.getNamespaceURI(prefix);
+    }
+
+    @Override
+    public String getNamespacePrefix(String uri) throws NamespaceException, RepositoryException {
+        return wrapped.getNamespacePrefix(uri);
+    }
+
+    @Override
+    public void logout() {
+        wrapped.logout();
+    }
+
+    @Override
+    public boolean isLive() {
+        return wrapped.isLive();
+    }
+
+    @Override
+    @SuppressWarnings("deprecation")
+    public void addLockToken(String lt) {
+        wrapped.addLockToken(lt);
+    }
+
+    @Override
+    @SuppressWarnings("deprecation")
+    public String[] getLockTokens() {
+        return wrapped.getLockTokens();
+    }
+
+    @Override
+    @SuppressWarnings("deprecation")
+    public void removeLockToken(String lt) {
+        wrapped.removeLockToken(lt);
+    }
+
+    @Override
+    public AccessControlManager getAccessControlManager()
+            throws UnsupportedRepositoryOperationException, RepositoryException {
+        return wrapped.getAccessControlManager();
+    }
+
+    @Override
+    public RetentionManager getRetentionManager() throws UnsupportedRepositoryOperationException, RepositoryException {
+        return wrapped.getRetentionManager();
+    }
+}

Added: sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/package-info.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/package-info.java?rev=1756146&view=auto
==============================================================================
--- sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/package-info.java (added)
+++ sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/package-info.java Fri Aug 12 11:02:39 2016
@@ -0,0 +1,23 @@
+/*
+ * 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 SF 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.
+ */
+
+/**
+ * Contains an implementation of a SlingRepository based on Apache Jackrabbit Oak.
+ * The package is not exported.
+ */
+package org.apache.sling.jcr.oak.server;