jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From tri...@apache.org
Subject svn commit: r808923 [1/2] - in /jackrabbit/trunk/jackrabbit-core/src: main/java/org/apache/jackrabbit/core/ main/java/org/apache/jackrabbit/core/xml/ test/java/org/apache/jackrabbit/core/xml/
Date Fri, 28 Aug 2009 15:38:38 GMT
Author: tripod
Date: Fri Aug 28 15:38:38 2009
New Revision: 808923

URL: http://svn.apache.org/viewvc?rev=808923&view=rev
Log:
JCR-2195 Provide possibility to import protected items using Session/Workspace import functionality

Added:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/AccessControlImporter.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DefaultProtectedNodeImporter.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DefaultProtectedPropertyImporter.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ProtectedItemHandling.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ProtectedNodeImporter.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ProtectedPropertyImporter.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/xml/AccessControlImporterTest.java   (with props)
Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/PropInfo.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/SessionImporter.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/SysViewImportHandler.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/xml/TestAll.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java?rev=808923&r1=808922&r2=808923&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java Fri Aug 28 15:38:38 2009
@@ -51,6 +51,8 @@
 import org.apache.jackrabbit.core.version.InternalVersionManagerImpl;
 import org.apache.jackrabbit.core.xml.ImportHandler;
 import org.apache.jackrabbit.core.xml.SessionImporter;
+import org.apache.jackrabbit.core.xml.ProtectedItemHandling;
+import org.apache.jackrabbit.core.xml.AccessControlImporter;
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.Path;
 import org.apache.jackrabbit.spi.commons.conversion.DefaultNamePathResolver;
@@ -84,6 +86,7 @@
 import javax.jcr.UnsupportedRepositoryOperationException;
 import javax.jcr.ValueFactory;
 import javax.jcr.Workspace;
+import javax.jcr.ImportUUIDBehavior;
 import javax.jcr.lock.Lock;
 import javax.jcr.lock.LockException;
 import javax.jcr.nodetype.ConstraintViolationException;
@@ -1171,7 +1174,9 @@
                 ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD | ItemValidator.CHECK_RETENTION;
         getValidator().checkModify(parent, options, Permission.NONE);
 
-        SessionImporter importer = new SessionImporter(parent, this, uuidBehavior);
+        ProtectedItemHandling pi = new ProtectedItemHandling();
+        pi.register(new AccessControlImporter(this, this, false, ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW));
+        SessionImporter importer = new SessionImporter(parent, this, uuidBehavior, pi);
         return new ImportHandler(importer, this);
     }
 
@@ -1545,7 +1550,7 @@
     }
 
     /**
-     * @see javax.jcr.Session#hasCapability(String, Object, Map)
+     * @see javax.jcr.Session#hasCapability(String, Object, Object[]) 
      * @since JCR 2.0
      */
     public boolean hasCapability(String methodName, Object target, Object[] arguments)

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/AccessControlImporter.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/AccessControlImporter.java?rev=808923&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/AccessControlImporter.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/AccessControlImporter.java Fri Aug 28 15:38:38 2009
@@ -0,0 +1,348 @@
+/*
+ * 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.jackrabbit.core.xml;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.security.authorization.AccessControlConstants;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlManager;
+import org.apache.jackrabbit.api.JackrabbitSession;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.PropertyType;
+import javax.jcr.Value;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.Privilege;
+import javax.jcr.security.AccessControlPolicy;
+import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Stack;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.security.Principal;
+
+/**
+ * <code>AccessControlImporter</code> implements a
+ * <code>ProtectedNodeImporter</code> that is able to deal with access control
+ * content as defined by the default ac related node types present with
+ * jackrabbit-core.
+ */
+public class AccessControlImporter extends DefaultProtectedNodeImporter {
+
+    /**
+     * logger instance
+     */
+    private static final Logger log = LoggerFactory.getLogger(AccessControlImporter.class);
+
+    private static final int STATUS_UNDEFINED = 0;
+    private static final int STATUS_AC_FOLDER = 1;
+    private static final int STATUS_PRINCIPAL_AC = 2;
+    private static final int STATUS_ACL = 3;
+    private static final int STATUS_ACE = 4;
+
+    private static final Set<Name> ACE_NODETYPES = new HashSet<Name>(2);
+    static {
+        ACE_NODETYPES.add(AccessControlConstants.NT_REP_DENY_ACE);
+        ACE_NODETYPES.add(AccessControlConstants.NT_REP_GRANT_ACE);
+    }
+
+    private final AccessControlManager acMgr;
+    private final Stack<Integer> prevStatus = new Stack<Integer>();
+
+    private int status = STATUS_UNDEFINED;
+    private NodeImpl parent = null;
+
+    private boolean principalbased = false;
+
+    public AccessControlImporter(JackrabbitSession session, NamePathResolver resolver,
+                                 boolean isWorkspaceImport, int uuidBehavior) throws RepositoryException {
+        super(session, resolver, isWorkspaceImport, uuidBehavior);
+
+        acMgr = session.getAccessControlManager();
+    }
+
+    public boolean start(NodeImpl protectedParent) throws RepositoryException {
+        if (isStarted()) {
+            throw new IllegalStateException();
+        }
+        if (isWorkspaceImport) {
+            log.debug("AccessControlImporter may not be used with the WorkspaceImporter");
+            return false;
+        }
+        if (!protectedParent.getDefinition().isProtected()) {
+            log.debug("AccessControlImporter may not be started with a non-protected parent.");
+            return false;
+        }
+
+        if (AccessControlConstants.N_POLICY.equals(protectedParent.getQName())
+                && protectedParent.isNodeType(AccessControlConstants.NT_REP_ACL)) {
+            status = STATUS_ACL;
+        } else if (protectedParent.isNodeType(AccessControlConstants.NT_REP_ACCESS_CONTROL)) {
+            status = STATUS_AC_FOLDER;
+            principalbased = true;
+        } // else: nothing this importer can deal with.
+
+        if (isStarted()) {
+            parent = protectedParent;
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    public boolean start(NodeState protectedParent) throws IllegalStateException, RepositoryException {
+        if (isStarted()) {
+            throw new IllegalStateException();
+        }
+        if (isWorkspaceImport) {
+            log.debug("AccessControlImporter may not be used with the WorkspaceImporter");
+            return false;
+        }
+        return false;
+    }
+
+    public void end(NodeImpl protectedParent) throws RepositoryException {
+        if (!isStarted()) {
+            return;
+        }
+
+        if (!principalbased) {
+            checkStatus(STATUS_ACL, "");
+        } else {
+            checkStatus(STATUS_AC_FOLDER, "");
+            if (!prevStatus.isEmpty()) {
+                throw new ConstraintViolationException("Incomplete protected item tree: "+ prevStatus.size()+ " calls to 'endChildInfo' missing.");
+            }
+        }
+        reset();
+    }
+
+    public void end(NodeState protectedParent) throws IllegalStateException, ConstraintViolationException, RepositoryException {
+        // nothing to do. will never get here.
+    }
+
+    public void startChildInfo(NodeInfo childInfo, List<PropInfo> propInfos) throws RepositoryException {
+        if (!isStarted()) {
+            return;
+        }
+        
+        Name ntName = childInfo.getNodeTypeName();
+        int previousStatus = status;
+
+        if (!principalbased) {
+            checkStatus(STATUS_ACL, "Cannot handle childInfo " + childInfo + "; rep:ACL may only contain a single level of child nodes representing the ACEs");
+            addACE(childInfo, propInfos);
+            status = STATUS_ACE;
+        } else {
+            switch (status) {
+                case STATUS_AC_FOLDER:
+                    if (AccessControlConstants.NT_REP_ACCESS_CONTROL.equals(ntName)) {
+                        // yet another intermediate node -> keep status
+                    } else if (AccessControlConstants.NT_REP_PRINCIPAL_ACCESS_CONTROL.equals(ntName)) {
+                        // the start of a principal-based acl
+                        status = STATUS_PRINCIPAL_AC;
+                    } else {
+                        // illegal node type.
+                        throw new ConstraintViolationException("Unexpected node type " + ntName + ". Should be rep:AccessControl or rep:PrincipalAccessControl.");
+                    }
+                    checkIdMixins(childInfo);
+                    break;
+                case STATUS_PRINCIPAL_AC:
+                    if (AccessControlConstants.NT_REP_ACCESS_CONTROL.equals(ntName)) {
+                        // some intermediate path between principal paths.
+                        status = STATUS_AC_FOLDER;
+                    } else if (AccessControlConstants.NT_REP_PRINCIPAL_ACCESS_CONTROL.equals(ntName)) {
+                        // principal-based ac node underneath another one
+                        // keep status
+                    } else {
+                        // the start the acl definition itself
+                        checkDefinition(childInfo, AccessControlConstants.N_POLICY, AccessControlConstants.NT_REP_ACL);
+                        status = STATUS_ACL;
+                    }
+                    checkIdMixins(childInfo);
+                    break;
+                case STATUS_ACL:
+                    // nodeinfo must define an ACE
+                    addACE(childInfo, propInfos);
+                    status = STATUS_ACE;
+                    break;
+                default:
+                    throw new ConstraintViolationException("Cannot handle childInfo " + childInfo + "; inexpected status " + status + " .");
+
+            }
+        }
+        prevStatus.push(previousStatus);        
+    }
+
+    /**
+     * @throws javax.jcr.RepositoryException
+     */
+    public void endChildInfo() throws RepositoryException {
+        if (!isStarted()) {
+            return;
+        }
+
+        // if the protected imported is started at an existing protected node
+        // SessionImporter does not remember it on the stack of parents node.
+        if (!principalbased) {
+            // childInfo + props have already been handled
+            // -> assert valid status
+            // -> no further actions required.
+            checkStatus(STATUS_ACE, "Upon completion of a NodeInfo the status must be STATUS_ACE.");
+        }
+
+        // reset the status
+        status = prevStatus.pop();
+    }
+
+
+    private boolean isStarted() {
+        return status > STATUS_UNDEFINED;
+    }
+    
+    private void reset() {
+        status = STATUS_UNDEFINED;
+        parent = null;
+    }
+
+    private void checkStatus(int expectedStatus, String message) throws ConstraintViolationException {
+        if (status != expectedStatus) {
+            throw new ConstraintViolationException(message);
+        }
+    }
+
+    private static void checkDefinition(NodeInfo nInfo, Name expName, Name expNodeTypeName) throws ConstraintViolationException {
+        if (expName != null && !expName.equals(nInfo.getName())) {
+            // illegal name
+            throw new ConstraintViolationException("Unexpected Node name "+ nInfo.getName() +". Node name should be " + expName + ".");
+        }
+        if (expNodeTypeName != null && !expNodeTypeName.equals(nInfo.getNodeTypeName())) {
+            // illegal name
+            throw new ConstraintViolationException("Unexpected node type " + nInfo.getNodeTypeName() + ". Node type should be " + expNodeTypeName + ".");
+        }
+    }
+
+    private static void checkIdMixins(NodeInfo nInfo) throws ConstraintViolationException {
+        // neither explicit id NOR mixin types may be present.
+        Name[] mixins = nInfo.getMixinNames();
+        NodeId id = nInfo.getId();
+        if (id != null || mixins != null) {
+            throw new ConstraintViolationException("The node represented by NodeInfo " + nInfo + " may neither be referenceable nor have mixin types.");
+        }
+    }
+
+    private void addACE(NodeInfo childInfo, List<PropInfo> propInfos) throws RepositoryException, UnsupportedRepositoryOperationException {
+
+        // node type may only be rep:GrantACE or rep:DenyACE
+        Name ntName = childInfo.getNodeTypeName();
+        if (!ACE_NODETYPES.contains(ntName)) {
+            throw new ConstraintViolationException("Cannot handle childInfo " + childInfo + "; expected a valid, applicable rep:ACE node definition.");
+        }
+
+        checkIdMixins(childInfo);
+
+        boolean isAllow = AccessControlConstants.NT_REP_GRANT_ACE.equals(ntName);
+        Principal principal = null;
+        Privilege[] privileges = null;
+        Map<String, TextValue> restrictions = new HashMap<String, TextValue>();
+
+        for (PropInfo pInfo : propInfos) {
+            Name name = pInfo.getName();
+            if (AccessControlConstants.P_PRINCIPAL_NAME.equals(name)) {
+                Value[] values = pInfo.getValues(PropertyType.STRING, resolver);
+                if (values == null || values.length != 1) {
+                    throw new ConstraintViolationException("");
+                }
+                principal = session.getPrincipalManager().getPrincipal(values[0].getString());
+            } else if (AccessControlConstants.P_PRIVILEGES.equals(name)) {
+                Value[] values = pInfo.getValues(PropertyType.NAME, resolver);
+                privileges = new Privilege[values.length];
+                for (int i = 0; i < values.length; i++) {
+                    privileges[i] = acMgr.privilegeFromName(values[i].getString());
+                }
+            } else {
+                TextValue[] txtVls = pInfo.getTextValues();
+                for (TextValue txtV : txtVls) {
+                    restrictions.put(resolver.getJCRName(name), txtV);
+                }
+            }
+        }
+
+
+        // try to access policies
+        List<AccessControlPolicy> policies = new ArrayList<AccessControlPolicy>();
+        if (!principalbased) {
+            // no need to retrieve the applicable policies as the policy node
+            // itself is the start point of the protected import.
+            policies.addAll(Arrays.asList(acMgr.getPolicies(parent.getParent().getPath())));
+        } else {
+            if (acMgr instanceof JackrabbitAccessControlManager) {
+                JackrabbitAccessControlManager jacMgr = (JackrabbitAccessControlManager) acMgr;
+                policies.addAll(Arrays.asList(jacMgr.getPolicies(principal)));
+                policies.addAll(Arrays.asList(jacMgr.getApplicablePolicies(principal)));
+            }
+        }
+
+        for (AccessControlPolicy policy : policies) {
+            if (policy instanceof JackrabbitAccessControlList) {
+                JackrabbitAccessControlList acl = (JackrabbitAccessControlList) policy;
+                // test if this acl can be used to apply the ACE
+                boolean matches;
+                if (!principalbased) {
+                    // resource-based the acl-path must correspond to the path
+                    // of the start-point of the protected import that was the
+                    // policy node itself.
+                    matches = parent.getParent().getPath().equals(acl.getPath());
+                } else {
+                    // principal based acl: just try the first one (TODO: check again)
+                    matches = true;
+                }
+
+                if (matches) {
+                    Map<String, Value> restr = new HashMap<String, Value>();
+                    for (String restName : acl.getRestrictionNames()) {
+                        TextValue txtVal = restrictions.remove(restName);
+                        if (txtVal != null) {
+                            restr.put(restName, txtVal.getValue(acl.getRestrictionType(restName), resolver));
+                        }
+                    }
+                    if (!restrictions.isEmpty()) {
+                        throw new ConstraintViolationException("ACE childInfo contained restrictions that could not be applied.");
+                    }
+                    acl.addEntry(principal, privileges, isAllow, restr);
+                    acMgr.setPolicy(acl.getPath(), acl);
+                    return;
+                }
+
+            }
+        }
+
+        // could not apply the ACE. No suitable ACL found.
+        throw new ConstraintViolationException("Cannot handle childInfo " + childInfo + "; No policy found to apply the ACE.");        
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/AccessControlImporter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/AccessControlImporter.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev Url

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DefaultProtectedNodeImporter.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DefaultProtectedNodeImporter.java?rev=808923&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DefaultProtectedNodeImporter.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DefaultProtectedNodeImporter.java Fri Aug 28 15:38:38 2009
@@ -0,0 +1,101 @@
+/*
+ * 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.jackrabbit.core.xml;
+
+import java.util.List;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.api.JackrabbitSession;
+import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
+
+/**
+ * Default implementation that isn't able to handle any protected nodes.
+ */
+public class DefaultProtectedNodeImporter implements ProtectedNodeImporter {
+
+    protected final JackrabbitSession session;
+
+    protected final NamePathResolver resolver;
+
+    protected final boolean isWorkspaceImport;
+
+    protected final int uuidBehavior;
+
+    public DefaultProtectedNodeImporter(JackrabbitSession session,
+                                 NamePathResolver resolver,
+                                 boolean isWorkspaceImport,
+                                 int uuidBehavior) {
+        this.session = session;
+        this.resolver = resolver;
+        this.isWorkspaceImport = isWorkspaceImport;
+        this.uuidBehavior = uuidBehavior;
+    }
+
+
+    /**
+     * Always returns <code>false</code>.
+     *
+     * @see ProtectedNodeImporter#start(org.apache.jackrabbit.core.NodeImpl)
+     */
+    public boolean start(NodeImpl protectedParent) throws RepositoryException {
+        return false;
+    }
+
+    /**
+     * Always returns <code>false</code>.
+     *
+     * @see ProtectedNodeImporter#start(org.apache.jackrabbit.core.state.NodeState)
+     */
+    public boolean start(NodeState protectedParent) throws RepositoryException {
+        return false;
+    }
+
+    /**
+     * Does nothing.
+     *
+     * @see ProtectedNodeImporter#end(NodeImpl)
+     */
+    public void end(NodeImpl protectedParent) throws RepositoryException {
+    }
+
+    /**
+     * Does nothing.
+     *
+     * @see ProtectedNodeImporter#end(NodeState)
+     */
+    public void end(NodeState protectedParent) throws RepositoryException {
+    }
+
+    /**
+     * Does nothing.
+     *
+     * @see ProtectedNodeImporter#startChildInfo(NodeInfo, List)
+     */
+    public void startChildInfo(NodeInfo childInfo, List<PropInfo> propInfos) throws RepositoryException {
+    }
+
+    /**
+     * Does nothing.
+     *
+     * @see ProtectedNodeImporter#endChildInfo()
+     */
+    public void endChildInfo() throws RepositoryException {
+    }
+}
\ No newline at end of file

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DefaultProtectedNodeImporter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DefaultProtectedNodeImporter.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev Url

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DefaultProtectedPropertyImporter.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DefaultProtectedPropertyImporter.java?rev=808923&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DefaultProtectedPropertyImporter.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DefaultProtectedPropertyImporter.java Fri Aug 28 15:38:38 2009
@@ -0,0 +1,63 @@
+/*
+ * 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.jackrabbit.core.xml;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.nodetype.PropDef;
+import org.apache.jackrabbit.api.JackrabbitSession;
+import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
+
+/**
+ * Default implementation that isn't able to handle any protected properties.
+ */
+public class DefaultProtectedPropertyImporter implements ProtectedPropertyImporter {
+
+    protected final JackrabbitSession session;
+
+    protected final NamePathResolver resolver;
+
+    protected final boolean isWorkspaceImport;
+
+    public DefaultProtectedPropertyImporter(JackrabbitSession session,
+                                 NamePathResolver resolver,
+                                 boolean isWorkspaceImport) {
+        this.session = session;
+        this.resolver = resolver;
+        this.isWorkspaceImport = isWorkspaceImport;
+    }
+
+    /**
+     * Always returns <code>false</code>.
+     *
+     * @see ProtectedPropertyImporter#handlePropInfo(org.apache.jackrabbit.core.NodeImpl, PropInfo, org.apache.jackrabbit.core.nodetype.PropDef)
+     */
+    public boolean handlePropInfo(NodeImpl parent, PropInfo protectedPropInfo, PropDef def) {
+        return false;
+    }
+
+    /**
+     * Always returns <code>false</code>.
+     *
+     * @see ProtectedPropertyImporter#handlePropInfo(org.apache.jackrabbit.core.state.NodeState, PropInfo, PropDef)
+     */
+    public boolean handlePropInfo(NodeState parent, PropInfo protectedPropInfo, PropDef def) throws RepositoryException {
+        return false;
+    }
+}
\ No newline at end of file

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DefaultProtectedPropertyImporter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DefaultProtectedPropertyImporter.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev Url

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java?rev=808923&r1=808922&r2=808923&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java Fri Aug 28 15:38:38 2009
@@ -16,28 +16,31 @@
  */
 package org.apache.jackrabbit.core.xml;
 
+import java.io.IOException;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Stack;
+
+import javax.jcr.NamespaceException;
+import javax.jcr.Node;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.ValueFactory;
+
 import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.commons.conversion.IllegalNameException;
 import org.apache.jackrabbit.spi.commons.conversion.NameException;
 import org.apache.jackrabbit.spi.commons.conversion.NameParser;
-import org.apache.jackrabbit.spi.commons.conversion.IllegalNameException;
 import org.apache.jackrabbit.spi.commons.name.NameConstants;
 import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
-import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.util.ISO9075;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.xml.sax.Attributes;
 import org.xml.sax.SAXException;
 
-import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-import javax.jcr.NamespaceException;
-import javax.jcr.ValueFactory;
-import java.io.IOException;
-import java.io.Reader;
-import java.util.ArrayList;
-import java.util.Stack;
-
 /**
  * <code>DocViewImportHandler</code> processes Document View XML SAX events
  * and 'translates' them into <code>{@link Importer}</code> method calls.
@@ -58,7 +61,8 @@
     /**
      * Constructs a new <code>DocViewImportHandler</code>.
      *
-     * @param importer
+     * @param importer the importer
+     * @param valueFactory a value factory
      */
     DocViewImportHandler(Importer importer, ValueFactory valueFactory) {
         super(importer, valueFactory);
@@ -211,7 +215,7 @@
     /**
      * {@inheritDoc}
      * <p/>
-     * See also {@link DocViewSAXEventGenerator#leavingProperties(javax.jcr.Node, int)}
+     * See also {@link org.apache.jackrabbit.commons.xml.Exporter#exportProperties(Node)}
      * regarding special handling of multi-valued properties on export.
      */
     public void startElement(String namespaceURI, String localName,
@@ -230,7 +234,7 @@
             Name nodeTypeName = null;
             Name[] mixinTypes = null;
 
-            ArrayList<PropInfo> props = new ArrayList<PropInfo>(atts.getLength());
+            List<PropInfo> props = new ArrayList<PropInfo>(atts.getLength());
             for (int i = 0; i < atts.getLength(); i++) {
                 if (atts.getURI(i).equals(Name.NS_XMLNS_URI)) {
                     // skip namespace declarations reported as attributes
@@ -320,7 +324,7 @@
         // process buffered character data
         processCharacters();
 
-        NodeInfo node = (NodeInfo) stack.peek();
+        NodeInfo node = stack.peek();
         try {
             // call Importer
             importer.endNode(node);

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/PropInfo.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/PropInfo.java?rev=808923&r1=808922&r2=808923&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/PropInfo.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/PropInfo.java Fri Aug 28 15:38:38 2009
@@ -16,23 +16,15 @@
  */
 package org.apache.jackrabbit.core.xml;
 
-import javax.jcr.ItemExistsException;
 import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
 import javax.jcr.Value;
-import javax.jcr.ValueFormatException;
 import javax.jcr.nodetype.ConstraintViolationException;
 
-import org.apache.jackrabbit.core.BatchedItemOperations;
 import org.apache.jackrabbit.core.NodeImpl;
-import org.apache.jackrabbit.core.id.PropertyId;
 import org.apache.jackrabbit.core.nodetype.EffectiveNodeType;
-import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
 import org.apache.jackrabbit.core.nodetype.PropDef;
 import org.apache.jackrabbit.core.state.NodeState;
-import org.apache.jackrabbit.core.state.PropertyState;
-import org.apache.jackrabbit.core.util.ReferenceChangeTracker;
-import org.apache.jackrabbit.core.value.InternalValue;
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
 import org.slf4j.Logger;
@@ -51,11 +43,6 @@
 public class PropInfo {
 
     /**
-     * Logger instance.
-     */
-    private static Logger log = LoggerFactory.getLogger(PropInfo.class);
-
-    /**
      * Name of the property being imported.
      */
     private final Name name;
@@ -87,12 +74,12 @@
      * Disposes all values contained in this property.
      */
     public void dispose() {
-        for (int i = 0; i < values.length; i++) {
-            values[i].dispose();
+        for (TextValue value : values) {
+            value.dispose();
         }
     }
 
-    private int getTargetType(PropDef def) {
+    public int getTargetType(PropDef def) {
         int target = def.getRequiredType();
         if (target != PropertyType.UNDEFINED) {
             return target;
@@ -103,7 +90,7 @@
         }
     }
 
-    private PropDef getApplicablePropertyDef(EffectiveNodeType ent)
+    public PropDef getApplicablePropertyDef(EffectiveNodeType ent)
             throws ConstraintViolationException {
         if (values.length == 1) {
             // could be single- or multi-valued (n == 1)
@@ -114,116 +101,23 @@
         }
     }
 
-    public void apply(
-            NodeImpl node, NamePathResolver resolver,
-            ReferenceChangeTracker refTracker) throws RepositoryException {
-        // find applicable definition
-        PropDef def = getApplicablePropertyDef(node.getEffectiveNodeType());
-        if (def.isProtected()) {
-            // skip protected property
-            log.debug("skipping protected property " + name);
-            return;
-        }
-
-        // convert serialized values to Value objects
-        Value[] va = new Value[values.length];
-        int targetType = getTargetType(def);
-        for (int i = 0; i < values.length; i++) {
-            va[i] = values[i].getValue(targetType, resolver);
-        }
-
-        // multi- or single-valued property?
-        if (va.length == 1 && !def.isMultiple()) {
-            Exception e = null;
-            try {
-                // set single-value
-                node.setProperty(name, va[0]);
-            } catch (ValueFormatException vfe) {
-                e = vfe;
-            } catch (ConstraintViolationException cve) {
-                e = cve;
-            }
-            if (e != null) {
-                // setting single-value failed, try setting value array
-                // as a last resort (in case there are ambiguous property
-                // definitions)
-                node.setProperty(name, va, type);
-            }
-        } else {
-            // can only be multi-valued (n == 0 || n > 1)
-            node.setProperty(name, va, type);
-        }
-        if (type == PropertyType.REFERENCE
-                || type == PropertyType.WEAKREFERENCE) {
-            // store reference for later resolution
-            refTracker.processedReference(node.getProperty(name));
-        }
+    public Name getName() {
+        return name;
     }
 
-    public void apply(
-            NodeState node, BatchedItemOperations itemOps,
-            NodeTypeRegistry ntReg, ReferenceChangeTracker refTracker)
-            throws RepositoryException {
-        PropertyState prop = null;
-        PropDef def = null;
-
-        if (node.hasPropertyName(name)) {
-            // a property with that name already exists...
-            PropertyId idExisting = new PropertyId(node.getNodeId(), name);
-            prop = (PropertyState) itemOps.getItemState(idExisting);
-            def = ntReg.getPropDef(prop.getDefinitionId());
-            if (def.isProtected()) {
-                // skip protected property
-                log.debug("skipping protected property "
-                        + itemOps.safeGetJCRPath(idExisting));
-                return;
-            }
-            if (!def.isAutoCreated()
-                    || (prop.getType() != type && type != PropertyType.UNDEFINED)
-                    || def.isMultiple() != prop.isMultiValued()) {
-                throw new ItemExistsException(itemOps.safeGetJCRPath(prop.getPropertyId()));
-            }
-        } else {
-            // there's no property with that name,
-            // find applicable definition
-            def = getApplicablePropertyDef(itemOps.getEffectiveNodeType(node));
-            if (def.isProtected()) {
-                // skip protected property
-                log.debug("skipping protected property " + name);
-                return;
-            }
-
-            // create new property
-            prop = itemOps.createPropertyState(node, name, type, def);
-        }
+    public int getType() {
+        return type;
+    }
 
-        // check multi-valued characteristic
-        if (values.length != 1 && !def.isMultiple()) {
-            throw new ConstraintViolationException(itemOps.safeGetJCRPath(prop.getPropertyId())
-                    + " is not multi-valued");
-        }
+    public TextValue[] getTextValues() {
+        return values;        
+    }
 
-        // convert serialized values to InternalValue objects
-        int targetType = getTargetType(def);
-        InternalValue[] iva = new InternalValue[values.length];
+    public Value[] getValues(int targetType, NamePathResolver resolver) throws RepositoryException {
+        Value[] va = new Value[values.length];
         for (int i = 0; i < values.length; i++) {
-            iva[i] = values[i].getInternalValue(targetType);
-        }
-
-        // set values
-        prop.setValues(iva);
-
-        // make sure property is valid according to its definition
-        itemOps.validate(prop);
-
-        if (prop.getType() == PropertyType.REFERENCE
-                || prop.getType() == PropertyType.WEAKREFERENCE) {
-            // store reference for later resolution
-            refTracker.processedReference(prop);
+            va[i] = values[i].getValue(targetType, resolver);
         }
-
-        // store property
-        itemOps.store(prop);
+        return va;
     }
-
 }

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ProtectedItemHandling.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ProtectedItemHandling.java?rev=808923&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ProtectedItemHandling.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ProtectedItemHandling.java Fri Aug 28 15:38:38 2009
@@ -0,0 +1,117 @@
+/*
+ * 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.jackrabbit.core.xml;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.nodetype.PropDef;
+import org.apache.jackrabbit.core.state.NodeState;
+
+/**
+ * Provides a registry like helper class for the {@link ProtectedPropertyImporter}
+ * and {@link ProtectedNodeImporter} classes.
+ */
+public class ProtectedItemHandling implements ProtectedPropertyImporter {
+
+    private final List<ProtectedNodeImporter> nodeImporters = new ArrayList<ProtectedNodeImporter>();
+
+    private final List<ProtectedPropertyImporter> propImporters = new ArrayList<ProtectedPropertyImporter>();
+
+    public void register(ProtectedNodeImporter ni) {
+        nodeImporters.add(ni);
+    }
+
+    public void register(ProtectedPropertyImporter pi) {
+        propImporters.add(pi);
+    }
+
+    /**
+     * Selects the node importer that can handle the give parent by
+     * invoking it's {@link ProtectedNodeImporter#start(NodeImpl)} method.
+
+     * @param protectedParent the parent node
+     * @return the importer if it handles the node
+     * @throws IllegalStateException if an error occurs
+     * @throws RepositoryException if an error occurs
+     */
+    public ProtectedNodeImporter accept(NodeImpl protectedParent)
+            throws IllegalStateException, RepositoryException {
+        for (ProtectedNodeImporter ni: nodeImporters) {
+            if (ni.start(protectedParent)) {
+                return ni;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Selects the node importer that can handle the give parent by
+     * invoking it's {@link ProtectedNodeImporter#start(NodeState)} method.
+
+     * @param protectedParent the parent node
+     * @return the importer if it handles the node
+     * @throws IllegalStateException if an error occurs
+     * @throws RepositoryException if an error occurs
+     */
+    public ProtectedNodeImporter accept(NodeState protectedParent)
+            throws IllegalStateException, RepositoryException {
+        for (ProtectedNodeImporter ni: nodeImporters) {
+            if (ni.start(protectedParent)) {
+                return ni;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Selects the property importer from the configured ones that can handle
+     * the prop info.
+     */
+    public boolean handlePropInfo(NodeImpl parent, PropInfo protectedPropInfo,
+                                  PropDef def)
+            throws RepositoryException {
+        for (ProtectedPropertyImporter pi: propImporters) {
+            if (pi.handlePropInfo(parent, protectedPropInfo, def)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Selects the property importer from the configured ones that can handle
+     * the prop info.
+     */
+    public boolean handlePropInfo(NodeState parent, PropInfo protectedPropInfo,
+                                  PropDef def)
+            throws RepositoryException {
+        for (ProtectedPropertyImporter pi: propImporters) {
+            if (pi.handlePropInfo(parent, protectedPropInfo, def)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
\ No newline at end of file

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ProtectedItemHandling.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ProtectedItemHandling.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev Url

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ProtectedNodeImporter.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ProtectedNodeImporter.java?rev=808923&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ProtectedNodeImporter.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ProtectedNodeImporter.java Fri Aug 28 15:38:38 2009
@@ -0,0 +1,152 @@
+/*
+ * 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.jackrabbit.core.xml;
+
+import org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.state.NodeState;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.ConstraintViolationException;
+import java.util.List;
+
+/**
+ * <code>ProtectedNodeImporter</code> provides means to import protected
+ * <code>Node</code>s and the subtree defined below such nodes.
+ * <p/>
+ * The import of a protected tree is started by the <code>Importer</code> by
+ * calling {@link #start(NodeImpl)}. If the <code>ProtectedNodeImporter</code>
+ * is able to deal with that type of protected node, it is in charge of dealing
+ * with all subsequent child <code>NodeInfo</code>s present below the protected
+ * parent until {@link #end(NodeImpl)} is called. The latter resets this importer
+ * and makes it available for another protected import.
+ *
+ * TODO: check if references properties can be handled with the info present
+ */
+public interface ProtectedNodeImporter {
+
+    /**
+     * Notifies this importer about the existience of a protected node that
+     * has either been created (NEW) or has been found to be existing.
+     * This importer implementation is in charge of evaluating the nature of
+     * that protected node in order to determine, if it is able to handle
+     * subsequent protected or non-protected child nodes in the tree below
+     * that parent.
+     *
+     * @param protectedParent A protected node that has either been created
+     * during the current XML import or that has been found to be existing
+     * without allowing same-name siblings.
+     * @return <code>true</code> If this importer is able to deal with the
+     * tree that may be present below the given protected Node.
+     * @throws IllegalStateException If this method is called on
+     * this importer without having reached {@link #end(NodeImpl)}.
+     * @throws RepositoryException If an error occurs.
+     */
+    boolean start(NodeImpl protectedParent) throws IllegalStateException,
+            RepositoryException;
+
+    /**
+     * Notifies this importer about the existience of a protected node that
+     * has either been created (NEW) or has been found to be existing.
+     * This importer implementation is in charge of evaluating the nature of
+     * that protected node in order to determine, if it is able to handle
+     * subsequent protected or non-protected child nodes in the tree below
+     * that parent.
+     *
+     * @param protectedParent A protected node that has either been created
+     * during the current XML import or that has been found to be existing
+     * without allowing same-name siblings.
+     * @return <code>true</code> If this importer is able to deal with the
+     * tree that may be present below the given protected NodeState.
+     * @throws IllegalStateException If this method is called on
+     * this importer without having reached {@link #end(NodeState)}.
+     * @throws RepositoryException If an error occurs.
+     */
+    boolean start(NodeState protectedParent) throws IllegalStateException,
+            RepositoryException;
+
+
+    /**
+     * Informs this importer that the tree to be imported below
+     * <code>protectedParent</code> has bee completed. This allows the importer
+     * to be reset in order to be able to deal with another call to
+     * {@link #start(NodeImpl)}.<p/>
+     * If {@link #start(NodeImpl)} hasn't been called before, this method returns
+     * silently.
+     *
+     * @param protectedParent
+     * @throws IllegalStateException If end is called in an illegal state.
+     * @throws javax.jcr.nodetype.ConstraintViolationException If the tree
+     * that was imported is incomplete.
+     * @throws RepositoryException If another error occurs.
+     */
+    void end(NodeImpl protectedParent) throws IllegalStateException,
+            ConstraintViolationException, RepositoryException;
+
+    /**
+     * Informs this importer that the tree to be imported below
+     * <code>protectedParent</code> has bee completed. This allows the importer
+     * to be reset in order to be able to deal with another call to
+     * {@link #start(NodeState)}.<p/>
+     * If {@link #start(NodeState)} hasn't been called before, this method returns
+     * silently.
+     *
+     * @param protectedParent
+     * @throws IllegalStateException If end is called in an illegal state.
+     * @throws javax.jcr.nodetype.ConstraintViolationException If the tree
+     * that was imported is incomplete.
+     * @throws RepositoryException If another error occurs.
+     */
+    void end(NodeState protectedParent) throws IllegalStateException,
+            ConstraintViolationException, RepositoryException;
+
+    /**
+     * Informs this importer about a new <code>childInfo</code> and it's properties.
+     * If the importer is able to successfully import the given information
+     * this method returns silently. Otherwise
+     * <code>ConstraintViolationException</code> is thrown, in which case the
+     * whole import fails.<p/>
+     * In case this importer deals with multiple levels of nodes, it is in
+     * charge of maintaining the hierarchical structure (see also {#link endChildInfo()}. 
+     * <p/>
+     * If {@link #start(NodeImpl)} hasn't been called before, this method returns
+     * silently.
+     *
+     * @param childInfo
+     * @param propInfos
+     * @throws IllegalStateException If called in an illegal state.
+     * @throws javax.jcr.nodetype.ConstraintViolationException If the given
+     * infos contain invalid or incomplete data and therefore cannot be properly
+     * handled by this importer.
+     * @throws RepositoryException If another error occurs.
+     */
+    void startChildInfo(NodeInfo childInfo, List<PropInfo> propInfos)
+            throws IllegalStateException, ConstraintViolationException, RepositoryException;
+
+    /**
+     * Informs this importer about the end of a child info.
+     * <p/>
+     * If {@link #start(NodeImpl)} hasn't been called before, this method returns
+     * silently.
+     * 
+     * @throws IllegalStateException If end is called in an illegal state.
+     * @throws javax.jcr.nodetype.ConstraintViolationException If this method
+     * is called before all required child information has been imported.
+     * @throws RepositoryException If another error occurs.
+     */
+    void endChildInfo() throws RepositoryException;
+
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ProtectedNodeImporter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ProtectedNodeImporter.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev Url

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ProtectedPropertyImporter.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ProtectedPropertyImporter.java?rev=808923&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ProtectedPropertyImporter.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ProtectedPropertyImporter.java Fri Aug 28 15:38:38 2009
@@ -0,0 +1,63 @@
+/*
+ * 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.jackrabbit.core.xml;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.nodetype.PropDef;
+import org.apache.jackrabbit.core.state.NodeState;
+
+/**
+ * <code>ProtectedPropertyImporter</code> is in charge of importing single
+ * properties whith a protected <code>PropDef</code>.
+ *
+ * @see ProtectedNodeImporter for an abstract class used to import protected
+ * nodes and the subtree below them.
+ */
+public interface ProtectedPropertyImporter {
+
+    /**
+     * Handles a single protected property.
+     *
+     * @param parent The affected parent node.
+     * @param protectedPropInfo The <code>PropInfo</code> to be imported.
+     * @param def The property definition determined by the importer that
+     * calls this method.
+     * @return <code>true</code> If the property could be successfully imported;
+     * <code>false</code> otherwise.
+     * @throws RepositoryException If an error occurs.
+     */
+    boolean handlePropInfo(NodeImpl parent, PropInfo protectedPropInfo, PropDef def)
+            throws RepositoryException;
+
+    /**
+     * Handles a single protected property.
+     *
+     * @param parent The affected parent node.
+     * @param protectedPropInfo The <code>PropInfo</code> to be imported.
+     * @param def The property definition determined by the importer that
+     * calls this method.
+     * @return <code>true</code> If the property could be successfully imported;
+     * <code>false</code> otherwise.
+     * @throws RepositoryException If an error occurs.
+     */
+    boolean handlePropInfo(NodeState parent, PropInfo protectedPropInfo, PropDef def)
+            throws RepositoryException;
+
+
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ProtectedPropertyImporter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ProtectedPropertyImporter.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev Url

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/SessionImporter.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/SessionImporter.java?rev=808923&r1=808922&r2=808923&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/SessionImporter.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/SessionImporter.java Fri Aug 28 15:38:38 2009
@@ -16,15 +16,9 @@
  */
 package org.apache.jackrabbit.core.xml;
 
-import org.apache.jackrabbit.core.id.NodeId;
-import org.apache.jackrabbit.core.NodeImpl;
-import org.apache.jackrabbit.core.SessionImpl;
-import org.apache.jackrabbit.core.security.authorization.Permission;
-import org.apache.jackrabbit.core.util.ReferenceChangeTracker;
-import org.apache.jackrabbit.spi.Name;
-import org.apache.jackrabbit.spi.commons.name.NameConstants;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Stack;
 
 import javax.jcr.AccessDeniedException;
 import javax.jcr.ImportUUIDBehavior;
@@ -34,11 +28,20 @@
 import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
 import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
 import javax.jcr.nodetype.ConstraintViolationException;
 import javax.jcr.nodetype.NodeDefinition;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Stack;
+
+import org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.jackrabbit.core.nodetype.PropDef;
+import org.apache.jackrabbit.core.security.authorization.Permission;
+import org.apache.jackrabbit.core.util.ReferenceChangeTracker;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.commons.name.NameConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * <code>SessionImporter</code> ...
@@ -51,7 +54,7 @@
     private final NodeImpl importTargetNode;
     private final int uuidBehavior;
 
-    private Stack parents;
+    private Stack<NodeImpl> parents;
 
     /**
      * helper object that keeps track of remapped uuid's and imported reference
@@ -60,26 +63,71 @@
     private final ReferenceChangeTracker refTracker;
 
     /**
+     * Importer for protected nodes.
+     */
+    private ProtectedNodeImporter currentNodeImporter;
+
+    /**
+     * Importer for protected items.
+     */
+    private final ProtectedItemHandling protectedItemHandling;
+
+    /**
      * Creates a new <code>SessionImporter</code> instance.
      *
-     * @param importTargetNode
-     * @param session
+     * @param importTargetNode the target node
+     * @param session          session
      * @param uuidBehavior     any of the constants declared by
      *                         {@link javax.jcr.ImportUUIDBehavior}
      */
     public SessionImporter(NodeImpl importTargetNode,
                            SessionImpl session,
                            int uuidBehavior) {
+        this(importTargetNode, session, uuidBehavior, null);
+    }
+
+    /**
+     * Creates a new <code>SessionImporter</code> instance.
+     *
+     * @param importTargetNode the target node
+     * @param session session
+     * @param uuidBehavior the uuid behaviro
+     * @param protectedItemHandling protected item handling
+     */
+    public SessionImporter(NodeImpl importTargetNode, SessionImpl session,
+                           int uuidBehavior,
+                           ProtectedItemHandling protectedItemHandling) {
         this.importTargetNode = importTargetNode;
         this.session = session;
         this.uuidBehavior = uuidBehavior;
 
+        this.protectedItemHandling = protectedItemHandling == null
+                ? new ProtectedItemHandling()
+                : protectedItemHandling;
         refTracker = new ReferenceChangeTracker();
 
-        parents = new Stack();
+        parents = new Stack<NodeImpl>();
         parents.push(importTargetNode);
     }
 
+    /**
+     * make sure the editing session is allowed create nodes with a
+     * specified node type (and ev. mixins),<br>
+     * NOTE: this check is not executed in a single place as the parent
+     * may change in case of
+     * {@link javax.jcr.ImportUUIDBehavior#IMPORT_UUID_COLLISION_REPLACE_EXISTING IMPORT_UUID_COLLISION_REPLACE_EXISTING}.
+     *  
+     * @param parent parent node
+     * @param nodeName the name
+     * @throws RepositoryException if an error occurs
+     */
+    protected void checkPermission(NodeImpl parent, Name nodeName)
+            throws RepositoryException {
+        if (!session.getAccessManager().isGranted(session.getQPath(parent.getPath()), nodeName, Permission.NODE_TYPE_MNGMT)) {
+            throw new AccessDeniedException("Insufficient permission.");
+        }
+    }
+
     protected NodeImpl createNode(NodeImpl parent,
                                   Name nodeName,
                                   Name nodeTypeName,
@@ -92,13 +140,47 @@
         node = parent.addNode(nodeName, nodeTypeName, id);
         // add mixins
         if (mixinNames != null) {
-            for (int i = 0; i < mixinNames.length; i++) {
-                node.addMixin(mixinNames[i]);
+            for (Name mixinName : mixinNames) {
+                node.addMixin(mixinName);
             }
         }
         return node;
     }
 
+
+    protected void createProperty(NodeImpl node, PropInfo pInfo, PropDef def) throws RepositoryException {
+        // convert serialized values to Value objects
+        Value[] va = pInfo.getValues(pInfo.getTargetType(def), session);
+
+        // multi- or single-valued property?
+        Name name = pInfo.getName();
+        int type = pInfo.getType();
+        if (va.length == 1 && !def.isMultiple()) {
+            Exception e = null;
+            try {
+                // set single-value
+                node.setProperty(name, va[0]);
+            } catch (ValueFormatException vfe) {
+                e = vfe;
+            } catch (ConstraintViolationException cve) {
+                e = cve;
+            }
+            if (e != null) {
+                // setting single-value failed, try setting value array
+                // as a last resort (in case there are ambiguous property
+                // definitions)
+                node.setProperty(name, va, type);
+            }
+        } else {
+            // can only be multi-valued (n == 0 || n > 1)
+            node.setProperty(name, va, type);
+        }
+        if (type == PropertyType.REFERENCE || type == PropertyType.WEAKREFERENCE) {
+            // store reference for later resolution
+            refTracker.processedReference(node.getProperty(name));
+        }
+    }
+
     protected NodeImpl resolveUUIDConflict(NodeImpl parent,
                                            NodeImpl conflicting,
                                            NodeInfo nodeInfo)
@@ -106,6 +188,7 @@
         NodeImpl node;
         if (uuidBehavior == ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW) {
             // create new with new uuid
+            checkPermission(parent, nodeInfo.getName());
             node = createNode(parent, nodeInfo.getName(),
                     nodeInfo.getNodeTypeName(), nodeInfo.getMixinNames(), null);
             // remember uuid mapping
@@ -131,6 +214,7 @@
             // remove conflicting
             conflicting.remove();
             // create new with given uuid
+            checkPermission(parent, nodeInfo.getName());
             node = createNode(parent, nodeInfo.getName(),
                     nodeInfo.getNodeTypeName(), nodeInfo.getMixinNames(),
                     nodeInfo.getId());
@@ -144,6 +228,7 @@
             parent = (NodeImpl) conflicting.getParent();
 
             // replace child node
+            checkPermission(parent, nodeInfo.getName());
             node = parent.replaceChildNode(nodeInfo.getId(), nodeInfo.getName(),
                     nodeInfo.getNodeTypeName(), nodeInfo.getMixinNames());
         } else {
@@ -165,9 +250,9 @@
     /**
      * {@inheritDoc}
      */
-    public void startNode(NodeInfo nodeInfo, List propInfos)
+    public void startNode(NodeInfo nodeInfo, List<PropInfo> propInfos)
             throws RepositoryException {
-        NodeImpl parent = (NodeImpl) parents.peek();
+        NodeImpl parent = parents.peek();
 
         // process node
 
@@ -178,16 +263,31 @@
         Name[] mixins = nodeInfo.getMixinNames();
 
         if (parent == null) {
+            log.debug("Skipping node: " + nodeName);
             // parent node was skipped, skip this child node too
             parents.push(null); // push null onto stack for skipped node
-            log.debug("Skipping node: " + nodeName);
+            // notify the p-i-importer
+            if (currentNodeImporter != null) {
+                currentNodeImporter.startChildInfo(nodeInfo, propInfos);
+            }
             return;
         }
 
-        // make sure the editing session is allowed create nodes with a
-        // specified node type (and ev. mixins)
-        if (!session.getAccessManager().isGranted(session.getQPath(parent.getPath()), nodeName, Permission.NODE_TYPE_MNGMT)) {
-            throw new AccessDeniedException("Insufficient permission.");
+        if (parent.getDefinition().isProtected()) {
+            // skip protected node
+            parents.push(null);
+            log.debug("Skipping protected node: " + nodeName);
+
+            // Notify the ProtectedNodeImporter about the start of a item
+            // tree that is protected by this parent. If it potentially is
+            // able to deal with it, notify it about the child node.
+            currentNodeImporter = protectedItemHandling.accept(parent);
+            if (currentNodeImporter != null) {
+                log.debug("Protected node -> delegated to ProtectedPropertyImporter");
+                currentNodeImporter.startChildInfo(nodeInfo, propInfos);
+            } /* else: p-i-Importer isn't able to deal with the protected tree.
+                 skip the tree below the protected parent */
+            return;
         }
 
         if (parent.hasNode(nodeName)) {
@@ -198,9 +298,21 @@
                 // existing doesn't allow same-name siblings,
                 // check for potential conflicts
                 if (def.isProtected() && existing.isNodeType(ntName)) {
-                    // skip protected node
-                    parents.push(null); // push null onto stack for skipped node
+                    /*
+                     use the existing node as parent for the possible subsequent
+                     import of a protected tree, that the protected node importer
+                     may or may not be able to deal with.
+                     -> upon the next 'startNode' the check for the parent being
+                        protected will notify the protected node importer.
+                     -> if the importer is able to deal with that node it needs
+                        to care of the complete subtree until it is notified
+                        during the 'endNode' call.
+                     -> if the import can't deal with that node or if that node
+                        is the a leaf in the tree to be imported 'end' will
+                        not have an effect on the importer, that was never started.
+                    */
                     log.debug("Skipping protected node: " + existing);
+                    parents.push(existing);
                     return;
                 }
                 if (def.isAutoCreated() && existing.isNodeType(ntName)) {
@@ -224,6 +336,7 @@
             // create node
             if (id == null) {
                 // no potential uuid conflict, always add new node
+                checkPermission(parent, nodeName);
                 node = createNode(parent, nodeName, ntName, mixins, null);
             } else {
                 // potential uuid conflict
@@ -239,11 +352,12 @@
                     if (node == null) {
                         // no new node has been created, so skip this node
                         parents.push(null); // push null onto stack for skipped node
-                        log.debug("skipping existing node " + nodeInfo.getName());
+                        log.debug("Skipping existing node " + nodeInfo.getName());
                         return;
                     }
                 } else {
                     // create new with given uuid
+                    checkPermission(parent, nodeName);
                     node = createNode(parent, nodeName, ntName, mixins, id);
                 }
             }
@@ -251,20 +365,44 @@
 
         // process properties
 
-        Iterator iter = propInfos.iterator();
-        while (iter.hasNext()) {
-            PropInfo pi = (PropInfo) iter.next();
-            pi.apply(node, session, refTracker);
+        for (PropInfo pi : propInfos) {
+            // find applicable definition
+            PropDef def = pi.getApplicablePropertyDef(node.getEffectiveNodeType());
+            if (def.isProtected()) {
+                // skip protected property
+                log.debug("Skipping protected property " + pi.getName());
+
+                // notify the ProtectedPropertyImporter.
+                if (protectedItemHandling.handlePropInfo(node, pi, def)) {
+                    // TODO: deal with reference props within the imported tree?                    
+                    log.debug("Protected property -> delegated to ProtectedPropertyImporter");
+                } // else: p-i-Importer isn't able to deal with this property
+            } else {
+                // regular property -> create the property
+                createProperty(node, pi, def);
+            }
         }
 
         parents.push(node);
     }
 
+
     /**
      * {@inheritDoc}
      */
     public void endNode(NodeInfo nodeInfo) throws RepositoryException {
-        parents.pop();
+        NodeImpl parent = parents.pop();
+        if (parent == null) {
+            if (currentNodeImporter != null) {
+                currentNodeImporter.endChildInfo();
+            }
+        } else if (parent.getDefinition().isProtected()) {
+            if (currentNodeImporter != null) {
+                currentNodeImporter.end(parent);
+                currentNodeImporter = null;
+            }
+            // TODO: deal with reference props within the imported tree?
+        }
     }
 
     /**

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/SysViewImportHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/SysViewImportHandler.java?rev=808923&r1=808922&r2=808923&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/SysViewImportHandler.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/SysViewImportHandler.java Fri Aug 28 15:38:38 2009
@@ -16,26 +16,29 @@
  */
 package org.apache.jackrabbit.core.xml;
 
-import org.apache.jackrabbit.spi.commons.conversion.NameException;
-import org.apache.jackrabbit.spi.Name;
-import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
-import org.apache.jackrabbit.spi.commons.name.NameConstants;
-import org.apache.jackrabbit.core.id.NodeId;
-import org.xml.sax.Attributes;
-import org.xml.sax.SAXException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Stack;
 
 import javax.jcr.InvalidSerializedDataException;
+import javax.jcr.NamespaceException;
 import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
-import javax.jcr.NamespaceException;
 import javax.jcr.ValueFactory;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Stack;
+
+import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.commons.conversion.NameException;
+import org.apache.jackrabbit.spi.commons.name.NameConstants;
+import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
 
 /**
  * <code>SysViewImportHandler</code>  ...
  */
+@SuppressWarnings({"ThrowableInstanceNeverThrown"})
 class SysViewImportHandler extends TargetImportHandler {
 
     /**
@@ -59,7 +62,8 @@
     /**
      * Constructs a new <code>SysViewImportHandler</code>.
      *
-     * @param importer
+     * @param importer the underlying importer
+     * @param valueFactory the value factory
      */
     SysViewImportHandler(Importer importer, ValueFactory valueFactory) {
         super(importer, valueFactory);
@@ -121,7 +125,7 @@
 
             if (!stack.isEmpty()) {
                 // process current node first
-                ImportState current = (ImportState) stack.peek();
+                ImportState current = stack.peek();
                 // need to start current node
                 if (!current.started) {
                     processNode(current, true, false);
@@ -223,7 +227,7 @@
             throws SAXException {
         Name name = NameFactoryImpl.getInstance().create(namespaceURI, localName);
         // check element name
-        ImportState state = (ImportState) stack.peek();
+        ImportState state = stack.peek();
         if (name.equals(NameConstants.SV_NODE)) {
             // sv:node element
             if (!state.started) {
@@ -242,7 +246,7 @@
             // check if all system properties (jcr:primaryType, jcr:uuid etc.)
             // have been collected and create node as necessary
             if (currentPropName.equals(NameConstants.JCR_PRIMARYTYPE)) {
-                BufferedStringValue val = (BufferedStringValue) currentPropValues.get(0);
+                BufferedStringValue val = currentPropValues.get(0);
                 String s = null;
                 try {
                     s = val.retrieve();
@@ -258,9 +262,7 @@
                 if (state.mixinNames == null) {
                     state.mixinNames = new ArrayList<Name>(currentPropValues.size());
                 }
-                for (int i = 0; i < currentPropValues.size(); i++) {
-                    BufferedStringValue val =
-                            (BufferedStringValue) currentPropValues.get(i);
+                for (BufferedStringValue val : currentPropValues) {
                     String s = null;
                     try {
                         s = val.retrieve();
@@ -275,7 +277,7 @@
                     }
                 }
             } else if (currentPropName.equals(NameConstants.JCR_UUID)) {
-                BufferedStringValue val = (BufferedStringValue) currentPropValues.get(0);
+                BufferedStringValue val = currentPropValues.get(0);
                 try {
                     state.uuid = val.retrieve();
                 } catch (IOException ioe) {
@@ -283,9 +285,9 @@
                 }
             } else {
                 PropInfo prop = new PropInfo(
-                        currentPropName, currentPropType,
-                        (TextValue[]) currentPropValues.toArray(
-                                new TextValue[currentPropValues.size()]));
+                        currentPropName,
+                        currentPropType,
+                        currentPropValues.toArray(new TextValue[currentPropValues.size()]));
                 state.props.add(prop);
             }
             // reset temp fields
@@ -316,7 +318,7 @@
         /**
          * list of mixin types of current node
          */
-        ArrayList<Name> mixinNames;
+        List<Name> mixinNames;
         /**
          * uuid of current node
          */
@@ -325,7 +327,7 @@
         /**
          * list of PropInfo instances representing properties of current node
          */
-        ArrayList<PropInfo> props = new ArrayList<PropInfo>();
+        List<PropInfo> props = new ArrayList<PropInfo>();
 
         /**
          * flag indicating whether startNode() has been called for current node

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java?rev=808923&r1=808922&r2=808923&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java Fri Aug 28 15:38:38 2009
@@ -16,22 +16,38 @@
  */
 package org.apache.jackrabbit.core.xml;
 
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Stack;
+
+import javax.jcr.ImportUUIDBehavior;
+import javax.jcr.ItemExistsException;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.lock.LockException;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.version.VersionException;
+
 import org.apache.jackrabbit.core.BatchedItemOperations;
 import org.apache.jackrabbit.core.HierarchyManager;
-import org.apache.jackrabbit.core.id.NodeId;
 import org.apache.jackrabbit.core.SessionImpl;
 import org.apache.jackrabbit.core.WorkspaceImpl;
+import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.jackrabbit.core.id.PropertyId;
 import org.apache.jackrabbit.core.nodetype.EffectiveNodeType;
 import org.apache.jackrabbit.core.nodetype.NodeDef;
 import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
 import org.apache.jackrabbit.core.nodetype.PropDef;
+import org.apache.jackrabbit.core.state.ChildNodeEntry;
 import org.apache.jackrabbit.core.state.NodeState;
 import org.apache.jackrabbit.core.state.PropertyState;
-import org.apache.jackrabbit.core.state.ChildNodeEntry;
 import org.apache.jackrabbit.core.util.ReferenceChangeTracker;
 import org.apache.jackrabbit.core.value.InternalValue;
-import org.apache.jackrabbit.core.version.VersionHistoryInfo;
 import org.apache.jackrabbit.core.version.InternalVersionManager;
+import org.apache.jackrabbit.core.version.VersionHistoryInfo;
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.Path;
 import org.apache.jackrabbit.spi.commons.conversion.MalformedPathException;
@@ -39,20 +55,6 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.jcr.ImportUUIDBehavior;
-import javax.jcr.ItemExistsException;
-import javax.jcr.ItemNotFoundException;
-import javax.jcr.PathNotFoundException;
-import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-import javax.jcr.lock.LockException;
-import javax.jcr.nodetype.ConstraintViolationException;
-import javax.jcr.version.VersionException;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Stack;
-
 /**
  * <code>WorkspaceImporter</code> ...
  */
@@ -83,8 +85,8 @@
      * Creates a new <code>WorkspaceImporter</code> instance.
      *
      * @param parentPath   target path where to add the imported subtree
-     * @param wsp
-     * @param ntReg
+     * @param wsp the workspace to operate on
+     * @param ntReg the node type registry
      * @param uuidBehavior flag that governs how incoming UUIDs are handled
      * @throws PathNotFoundException        if no node exists at
      *                                      <code>parentPath</code> or if the
@@ -129,11 +131,11 @@
     }
 
     /**
-     * @param parent
-     * @param conflicting
-     * @param nodeInfo
-     * @return
-     * @throws RepositoryException
+     * @param parent parent node state
+     * @param conflicting conflicting node state
+     * @param nodeInfo the node info
+     * @return the resolved node state
+     * @throws RepositoryException if an error occurs
      */
     protected NodeState resolveUUIDConflict(NodeState parent,
                                             NodeState conflicting,
@@ -291,8 +293,8 @@
      * Post-process imported node (initialize properties with special
      * semantics etc.)
      *
-     * @param node
-     * @throws RepositoryException
+     * @param node the node state
+     * @throws RepositoryException if an error occurs
      */
     protected void postProcessNode(NodeState node) throws RepositoryException {
         /**
@@ -344,6 +346,73 @@
         }
     }
 
+    protected void processProperty(NodeState node, PropInfo pInfo) throws RepositoryException {
+        PropertyState prop;
+        PropDef def;
+
+        Name name = pInfo.getName();
+        int type = pInfo.getType();
+
+        if (node.hasPropertyName(name)) {
+            // a property with that name already exists...
+            PropertyId idExisting = new PropertyId(node.getNodeId(), name);
+            prop = (PropertyState) itemOps.getItemState(idExisting);
+            def = ntReg.getPropDef(prop.getDefinitionId());
+            if (def.isProtected()) {
+                // skip protected property
+                log.debug("skipping protected property "
+                        + itemOps.safeGetJCRPath(idExisting));
+                return;
+            }
+            if (!def.isAutoCreated()
+                    || (prop.getType() != type && type != PropertyType.UNDEFINED)
+                    || def.isMultiple() != prop.isMultiValued()) {
+                throw new ItemExistsException(itemOps.safeGetJCRPath(prop.getPropertyId()));
+            }
+        } else {
+            // there's no property with that name,
+            // find applicable definition
+            def = pInfo.getApplicablePropertyDef(itemOps.getEffectiveNodeType(node));
+            if (def.isProtected()) {
+                // skip protected property
+                log.debug("skipping protected property " + name);
+                return;
+            }
+
+            // create new property
+            prop = itemOps.createPropertyState(node, name, type, def);
+        }
+
+        // check multi-valued characteristic
+        TextValue[] values = pInfo.getTextValues();
+        if (values.length != 1 && !def.isMultiple()) {
+            throw new ConstraintViolationException(itemOps.safeGetJCRPath(prop.getPropertyId())
+                    + " is not multi-valued");
+        }
+
+        // convert serialized values to InternalValue objects
+        int targetType = pInfo.getTargetType(def);
+        InternalValue[] iva = new InternalValue[values.length];
+        for (int i = 0; i < values.length; i++) {
+            iva[i] = values[i].getInternalValue(targetType);
+        }
+
+        // set values
+        prop.setValues(iva);
+
+        // make sure property is valid according to its definition
+        itemOps.validate(prop);
+
+        if (prop.getType() == PropertyType.REFERENCE
+                || prop.getType() == PropertyType.WEAKREFERENCE) {
+            // store reference for later resolution
+            refTracker.processedReference(prop);
+        }
+
+        // store property
+        itemOps.store(prop);
+    }
+    
     /**
      * Adds the the given property to a node unless the property already
      * exists.
@@ -400,7 +469,7 @@
             // check sanity of workspace/session first
             wsp.sanityCheck();
 
-            parent = (NodeState) parents.peek();
+            parent = parents.peek();
 
             // process node
 
@@ -515,8 +584,8 @@
             }
 
             // process properties
-            for (PropInfo pi : propInfos) {
-                pi.apply(node, itemOps, ntReg, refTracker);
+            for (PropInfo propInfo : propInfos) {
+                processProperty(node, propInfo);
             }
 
             // store affected nodes
@@ -544,7 +613,7 @@
             // the import has been aborted, get outta here...
             return;
         }
-        NodeState node = (NodeState) parents.pop();
+        NodeState node = parents.pop();
         if (node == null) {
             // node was skipped, nothing to do here
             return;



Mime
View raw message