You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by tr...@apache.org on 2009/08/28 17:38:38 UTC
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/
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;