SLING-1212 - upgrading to Jackrabbit 2. Also includes re-revert of SLING-1363 and implementation of SLING-1330. Thanks to Felix for getting this started.

git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@911430 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/pom.xml b/pom.xml
index d66fdca..cb6b01a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,9 +7,9 @@
     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
@@ -64,9 +64,6 @@
                         <Private-Package>
                             org.apache.sling.jcr.base.internal.*
                         </Private-Package>
-                        <Embed-Dependency>
-                            jackrabbit-jcr-rmi;inline=true
-                        </Embed-Dependency>
                     </instructions>
                 </configuration>
             </plugin>
@@ -90,21 +87,30 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.jcr.api</artifactId>
-            <version>2.0.6</version>
+            <version>2.0.7-SNAPSHOT</version>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>javax.jcr</groupId>
             <artifactId>jcr</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.jackrabbit</groupId>
-            <artifactId>jackrabbit-api</artifactId>
-            <version>1.5.0</version>
+            <version>2.0</version>
         </dependency>
         <dependency>
             <groupId>org.apache.jackrabbit</groupId>
             <artifactId>jackrabbit-jcr-rmi</artifactId>
-            <version>1.5.0</version>
+            <version>2.0.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.jackrabbit</groupId>
+            <artifactId>jackrabbit-api</artifactId>
+            <version>2.0.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.jackrabbit</groupId>
+            <artifactId>jackrabbit-jcr-commons</artifactId>
+            <version>2.0.0</version>
             <scope>provided</scope>
         </dependency>
         <!-- OSGi Libraries -->
diff --git a/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepository.java b/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepository.java
index b02b704..697fa70 100644
--- a/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepository.java
+++ b/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepository.java
@@ -27,9 +27,11 @@
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import javax.jcr.SimpleCredentials;
+import javax.jcr.Value;
 import javax.jcr.Workspace;
 
 import org.apache.jackrabbit.api.JackrabbitWorkspace;
+import org.apache.sling.jcr.api.NamespaceMapper;
 import org.apache.sling.jcr.api.SlingRepository;
 import org.apache.sling.jcr.base.internal.loader.Loader;
 import org.apache.sling.jcr.base.util.RepositoryAccessor;
@@ -39,6 +41,7 @@
 import org.osgi.framework.SynchronousBundleListener;
 import org.osgi.service.component.ComponentContext;
 import org.osgi.service.log.LogService;
+import org.osgi.util.tracker.ServiceTracker;
 
 /**
  * The <code>AbstractSlingRepository</code> is an abstract implementation of
@@ -135,6 +138,8 @@
     // the background thread constantly checking the repository
     private Thread repositoryPinger;
 
+    private ServiceTracker namespaceMapperTracker;
+
     protected AbstractSlingRepository() {
     }
 
@@ -247,7 +252,7 @@
             throw new RepositoryException(re.getMessage(), re);
         }
     }
-    
+
     /**
      * @param anonUser the user name of the anon user.
      * @return a Credentials implementation that represents the anon user.
@@ -256,7 +261,7 @@
         // NB: this method is overridden in the Jackrabbit Service bundle to avoid using the anon password. SLING-1282
         return new SimpleCredentials(anonUser, anonPass);
     }
-    
+
     /**
      * @param adminUser the name of the administrative user.
      * @return a Credentials implementation that represents the administrative user.
@@ -265,7 +270,7 @@
         // NB: this method is overridden in the Jackrabbit Service bundle to avoid using the admin password. SLING-1282
         return new SimpleCredentials(adminUser, adminPass);
     }
-     
+
 
 
     /*
@@ -298,6 +303,58 @@
         return new String[0];
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    public Value getDescriptorValue(String key) {
+        Repository repo = getRepository();
+        if (repo != null) {
+            return repo.getDescriptorValue(key);
+        }
+
+        log(LogService.LOG_ERROR, "getDescriptorValue: Repository not available");
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Value[] getDescriptorValues(String key) {
+        Repository repo = getRepository();
+        if (repo != null) {
+            return repo.getDescriptorValues(key);
+        }
+
+        log(LogService.LOG_ERROR, "getDescriptorValues: Repository not available");
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isSingleValueDescriptor(String key) {
+        Repository repo = getRepository();
+        if (repo != null) {
+            return repo.isSingleValueDescriptor(key);
+        }
+
+        log(LogService.LOG_ERROR, "isSingleValueDescriptor: Repository not available");
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isStandardDescriptor(String key) {
+        Repository repo = getRepository();
+        if (repo != null) {
+            return repo.isStandardDescriptor(key);
+        }
+
+        log(LogService.LOG_ERROR, "isStandardDescriptor: Repository not available");
+        return false;
+    }
+
     // ---------- logging ------------------------------------------------------
 
     protected void log(int level, String message) {
@@ -552,6 +609,9 @@
      * @throws nothing, but allow derived classes to throw any Exception
      */
     protected void activate(ComponentContext componentContext) throws Exception {
+        this.namespaceMapperTracker = new ServiceTracker(componentContext.getBundleContext(), NamespaceMapper.class.getName(), null);
+        this.namespaceMapperTracker.open();
+
         this.componentContext = componentContext;
 
         @SuppressWarnings("unchecked")
@@ -598,6 +658,7 @@
      * @param componentContext
      */
     protected void deactivate(ComponentContext componentContext) {
+        this.namespaceMapperTracker.close();
 
         componentContext.getBundleContext().removeBundleListener(this);
 
@@ -691,6 +752,14 @@
             // apply namespace mapping
             this.namespaceHandler.defineNamespacePrefixes(session);
         }
+
+        // call namespace mappers
+        Object[] nsMappers = namespaceMapperTracker.getServices();
+        if (nsMappers != null) {
+            for (int i = 0; i < nsMappers.length; i++) {
+                ((NamespaceMapper) nsMappers[i]).defineNamespacePrefixes(session);
+            }
+        }
     }
 
     // ---------- Background operation checking repository availability --------
diff --git a/src/main/java/org/apache/sling/jcr/base/NodeTypeLoader.java b/src/main/java/org/apache/sling/jcr/base/NodeTypeLoader.java
index f979709..b841ed5 100644
--- a/src/main/java/org/apache/sling/jcr/base/NodeTypeLoader.java
+++ b/src/main/java/org/apache/sling/jcr/base/NodeTypeLoader.java
@@ -20,14 +20,16 @@
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
 import java.net.URL;
 
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import javax.jcr.Workspace;
-import javax.jcr.nodetype.NodeTypeManager;
 
-import org.apache.jackrabbit.api.JackrabbitNodeTypeManager;
+import org.apache.jackrabbit.commons.cnd.CndImporter;
+import org.apache.jackrabbit.commons.cnd.ParseException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -108,37 +110,17 @@
      */
     public static boolean registerNodeType(Session session, InputStream source)
             throws IOException, RepositoryException {
-        final Workspace workspace = session.getWorkspace();
-        final NodeTypeManager ntm = workspace.getNodeTypeManager();
-        if (ntm instanceof JackrabbitNodeTypeManager) {
-            log.debug("Using Jackrabbit to import node types");
-            JackrabbitNodeTypeManager jntm = (JackrabbitNodeTypeManager) ntm;
-            try {
-                jntm.registerNodeTypes(source,
-                    JackrabbitNodeTypeManager.TEXT_X_JCR_CND);
-                return true;
-            } catch (RepositoryException re) {
-                Throwable t = re.getCause();
-                if (t != null
-                    && t.getClass().getName().endsWith(
-                        ".InvalidNodeTypeDefException")) {
-                    // hacky wacky: interpret message to check whether it is for
-                    // duplicate node type -> very bad, that this is the only
-                    // way to check !!!
-                    if (re.getCause().getMessage().indexOf("already exists") >= 0) {
-                        // alright, node types are already registered, ignore
-                        // this
-                        log.debug("Node types already registered...");
-                        return true;
-                    }
-                }
+        return registerNodeType(session, "cnd input stream", new InputStreamReader(source), false);
+    }
 
-                // get here to rethrow the RepositoryException
-                throw re;
-            }
+    public static boolean registerNodeType(Session session, String systemId, Reader reader, boolean reregisterExisting)
+        throws IOException, RepositoryException {
+        try {
+            Workspace wsp = session.getWorkspace();
+            CndImporter.registerNodeTypes(reader, systemId, wsp.getNodeTypeManager(), wsp.getNamespaceRegistry(), session.getValueFactory(), reregisterExisting);
+        } catch (ParseException e) {
+            throw new IOException("Unable to parse CND Input.", e);
         }
-
-        log.warn("Repository does not implement JackrabbitNodeTypeManager, cannot import node types");
-        return false;
+        return true;
     }
 }
diff --git a/src/main/java/org/apache/sling/jcr/base/internal/NamespaceMapper.java b/src/main/java/org/apache/sling/jcr/base/internal/NamespaceMapper.java
deleted file mode 100644
index 1d1a387..0000000
--- a/src/main/java/org/apache/sling/jcr/base/internal/NamespaceMapper.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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;
-
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
-/**
- * This interface is used to customize the namespace mapping of
- * a session.
- */
-public interface NamespaceMapper {
-
-    void defineNamespacePrefixes(Session session)
-    throws RepositoryException;
-}
diff --git a/src/main/java/org/apache/sling/jcr/base/internal/loader/Loader.java b/src/main/java/org/apache/sling/jcr/base/internal/loader/Loader.java
index cd5531f..2f71907 100644
--- a/src/main/java/org/apache/sling/jcr/base/internal/loader/Loader.java
+++ b/src/main/java/org/apache/sling/jcr/base/internal/loader/Loader.java
@@ -20,6 +20,7 @@
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -33,9 +34,9 @@
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 
+import org.apache.sling.jcr.api.NamespaceMapper;
 import org.apache.sling.jcr.base.AbstractSlingRepository;
 import org.apache.sling.jcr.base.NodeTypeLoader;
-import org.apache.sling.jcr.base.internal.NamespaceMapper;
 import org.osgi.framework.Bundle;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -188,6 +189,17 @@
             StringTokenizer tokener = new StringTokenizer(typesHeader, ",");
             while (tokener.hasMoreTokens()) {
                 String nodeTypeFile = tokener.nextToken().trim();
+                Map<String,String> nodeTypeFileParams = new HashMap<String,String>();
+                nodeTypeFileParams.put("reregister", "true");
+
+                if (nodeTypeFile.contains(";")) {
+                    int idx = nodeTypeFile.indexOf(';');
+                    String nodeTypeFileParam = nodeTypeFile.substring(idx + 1);
+                    String[] params = nodeTypeFileParam.split(":=");
+                    nodeTypeFileParams.put(params[0], params[1]);
+                    nodeTypeFile = nodeTypeFile.substring(0, idx);
+
+                }
 
                 URL mappingURL = bundle.getEntry(nodeTypeFile);
                 if (mappingURL == null) {
@@ -202,7 +214,9 @@
                 try {
                     // laod the node types
                     ins = mappingURL.openStream();
-                    NodeTypeLoader.registerNodeType(session, ins);
+                    String reregister = nodeTypeFileParams.get("reregister");
+                    boolean reregisterBool = Boolean.valueOf(reregister);
+                    NodeTypeLoader.registerNodeType(session, mappingURL.toString(), new InputStreamReader(ins), reregisterBool);
                     // log a message if retry is successful
                     if ( isRetry ) {
                         log.info("Retrytring to register node types from {} in bundle {} succeeded.",
diff --git a/src/main/java/org/apache/sling/jcr/base/util/AccessControlUtil.java b/src/main/java/org/apache/sling/jcr/base/util/AccessControlUtil.java
index 5b893c8..d84a0b7 100644
--- a/src/main/java/org/apache/sling/jcr/base/util/AccessControlUtil.java
+++ b/src/main/java/org/apache/sling/jcr/base/util/AccessControlUtil.java
@@ -27,13 +27,13 @@
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.security.AccessControlEntry;
+import javax.jcr.security.AccessControlException;
+import javax.jcr.security.AccessControlList;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.Privilege;
 
 import org.apache.jackrabbit.api.JackrabbitSession;
-import org.apache.jackrabbit.api.jsr283.security.AccessControlEntry;
-import org.apache.jackrabbit.api.jsr283.security.AccessControlException;
-import org.apache.jackrabbit.api.jsr283.security.AccessControlList;
-import org.apache.jackrabbit.api.jsr283.security.AccessControlManager;
-import org.apache.jackrabbit.api.jsr283.security.Privilege;
 import org.apache.jackrabbit.api.security.principal.PrincipalManager;
 import org.apache.jackrabbit.api.security.user.UserManager;