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 2014/01/22 06:49:46 UTC
svn commit: r1560258 - in /jackrabbit/commons/filevault/trunk/vault-core/src:
main/java/org/apache/jackrabbit/vault/fs/impl/io/
main/java/org/apache/jackrabbit/vault/fs/io/
main/java/org/apache/jackrabbit/vault/util/
test/java/org/apache/jackrabbit/vau...
Author: tripod
Date: Wed Jan 22 05:49:45 2014
New Revision: 1560258
URL: http://svn.apache.org/r1560258
Log:
JCRVLT-25 Implement AccessControllHandling MERGE and MERGE_PRESERVE
Added:
jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewAdapter.java
jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/JackrabbitACLImporter.java
jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/JcrSysViewTransformer.java
jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewNode.java
jackrabbit/commons/filevault/trunk/vault-core/src/test/resources/org/apache/jackrabbit/vault/packaging/integration/testpackages/mode_ac_test_c_merge.zip (with props)
jackrabbit/commons/filevault/trunk/vault-core/src/test/resources/org/apache/jackrabbit/vault/packaging/integration/testpackages/mode_ac_test_d.zip (with props)
jackrabbit/commons/filevault/trunk/vault-core/src/test/resources/org/apache/jackrabbit/vault/packaging/integration/testpackages/oak_ac_content_test.zip (with props)
Modified:
jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewSAXImporter.java
jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/AccessControlHandling.java
jackrabbit/commons/filevault/trunk/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/IntegrationTestBase.java
jackrabbit/commons/filevault/trunk/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/TestACLAndMerge.java
Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewAdapter.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewAdapter.java?rev=1560258&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewAdapter.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewAdapter.java Wed Jan 22 05:49:45 2014
@@ -0,0 +1,48 @@
+/*************************************************************************
+ * 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.vault.fs.impl.io;
+
+import org.apache.jackrabbit.vault.util.DocViewNode;
+import org.xml.sax.SAXException;
+
+/**
+ * {@code DocViewAdapter} is used by the {@link org.apache.jackrabbit.vault.fs.impl.io.DocViewSAXImporter} to handle
+ * special content that is not importable using "normal" JCR calls. For example users and other protected content
+ * needs to be imported using the {@link javax.jcr.Session#importXML(String, java.io.InputStream, int)} or similar.
+ */
+public interface DocViewAdapter {
+
+ /**
+ * Start node is invoked when the importer descends into an element.
+ * @param node the node
+ * @throws SAXException if an error occurrs
+ */
+ public void startNode(DocViewNode node) throws SAXException;
+
+ /**
+ * Ends node is invoked when the importer ascends from an element.
+ * @throws SAXException if an error occurrs.
+ */
+ public void endNode() throws SAXException;
+
+ /**
+ * Is called by the importer if the adapter is no longer used and must finalize the import.
+ * @throws SAXException if an error occurrs.
+ */
+ public void close() throws SAXException;
+
+}
\ No newline at end of file
Modified: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewSAXImporter.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewSAXImporter.java?rev=1560258&r1=1560257&r2=1560258&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewSAXImporter.java (original)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewSAXImporter.java Wed Jan 22 05:49:45 2014
@@ -46,9 +46,7 @@ import javax.jcr.nodetype.NodeType;
import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.spi.commons.conversion.DefaultNamePathResolver;
-import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
import org.apache.jackrabbit.spi.commons.name.NameConstants;
-import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
import org.apache.jackrabbit.spi.commons.namespace.NamespaceResolver;
import org.apache.jackrabbit.util.ISO9075;
import org.apache.jackrabbit.vault.fs.PropertyValueArtifact;
@@ -64,6 +62,7 @@ import org.apache.jackrabbit.vault.fs.io
import org.apache.jackrabbit.vault.fs.spi.ACLManagement;
import org.apache.jackrabbit.vault.fs.spi.ServiceProviderFactory;
import org.apache.jackrabbit.vault.fs.spi.UserManagement;
+import org.apache.jackrabbit.vault.util.DocViewNode;
import org.apache.jackrabbit.vault.util.DocViewProperty;
import org.apache.jackrabbit.vault.util.JcrConstants;
import org.apache.jackrabbit.vault.util.MimeTypes;
@@ -588,7 +587,7 @@ public class DocViewSAXImporter extends
Node node = stack.getNode();
if (node == null) {
stack = stack.push(null);
- SysViewTransformer xform = stack.getTransformer();
+ DocViewAdapter xform = stack.getAdapter();
if (xform != null) {
DocViewNode ni = new DocViewNode(name, label, attributes, npResolver);
xform.startNode(ni);
@@ -608,16 +607,14 @@ public class DocViewSAXImporter extends
try {
DocViewNode ni = new DocViewNode(name, label, attributes, npResolver);
if (aclManagement.isACLNodeType(ni.primary)) {
- if (aclHandling == AccessControlHandling.OVERWRITE
- || aclHandling == AccessControlHandling.MERGE
- || aclHandling == AccessControlHandling.MERGE_PRESERVE && !node.hasNode(ni.name)) {
- log.debug("ACL element detected. starting sysview transformation {}/{}", node.getPath(), name);
+ if (aclHandling != AccessControlHandling.CLEAR && aclHandling != AccessControlHandling.IGNORE) {
+ log.debug("ACL element detected. starting special transformation {}/{}", node.getPath(), name);
if (aclManagement.ensureAccessControllable(node)) {
log.info("Adding ACL element to non ACL parent - adding mixin: {}", node.getPath());
}
stack = stack.push(null);
- stack.transformer = new SysViewTransformer(node);
- stack.transformer.startNode(ni);
+ stack.adapter = new JackrabbitACLImporter(node, aclHandling);
+ stack.adapter.startNode(ni);
importInfo.onCreated(node.getPath() + "/" + ni.name);
} else {
stack = stack.push(null);
@@ -650,8 +647,8 @@ public class DocViewSAXImporter extends
} else {
log.debug("Authorizable element detected. starting sysview transformation {}/{}", node.getPath(), name);
stack = stack.push(null);
- stack.transformer = new SysViewTransformer(node);
- stack.transformer.startNode(ni);
+ stack.adapter = new JcrSysViewTransformer(node);
+ stack.adapter.startNode(ni);
importInfo.onCreated(node.getPath() + "/" + ni.name);
}
} else {
@@ -1057,14 +1054,14 @@ public class DocViewSAXImporter extends
NodeNameList childNames = stack.getChildNames();
Node node = stack.getNode();
if (node == null) {
- SysViewTransformer xform = stack.getTransformer();
- if (xform != null) {
- xform.endNode();
+ DocViewAdapter adapter = stack.getAdapter();
+ if (adapter != null) {
+ adapter.endNode();
}
// close transformer if last in stack
- if (stack.transformer != null) {
- stack.transformer.close();
- stack.transformer = null;
+ if (stack.adapter != null) {
+ stack.adapter.close();
+ stack.adapter = null;
log.debug("Sysview transformation complete.");
}
} else {
@@ -1238,9 +1235,9 @@ public class DocViewSAXImporter extends
private boolean isCheckedOut;
/**
- * sysview handler for special content
+ * adapter for special content
*/
- private SysViewTransformer transformer;
+ private DocViewAdapter adapter;
public StackElement(DocViewSAXImporter.StackElement parent, Node node) throws RepositoryException {
this.node = node;
@@ -1297,112 +1294,15 @@ public class DocViewSAXImporter extends
return parent;
}
- public void setTransformer(SysViewTransformer transformer) {
- this.transformer = transformer;
- }
-
- public SysViewTransformer getTransformer() {
- if (transformer != null) {
- return transformer;
+ public DocViewAdapter getAdapter() {
+ if (adapter != null) {
+ return adapter;
}
- return parent == null ? null : parent.getTransformer();
+ return parent == null ? null : parent.getAdapter();
}
}
- private static class SysViewTransformer {
-
- /**
- * sysview handler for special content
- */
- private ContentHandler handler;
-
- private SysViewTransformer(Node node) throws RepositoryException, SAXException {
- Session session = node.getSession();
- handler = session.getImportContentHandler(
- node.getPath(),
- ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING);
- // first define the current namespaces
- String[] prefixes = session.getNamespacePrefixes();
- handler.startDocument();
- for (String prefix: prefixes) {
- handler.startPrefixMapping(prefix, session.getNamespaceURI(prefix));
- }
- }
-
- public void close() throws SAXException {
- handler.endDocument();
- }
-
- public void startNode(DocViewNode ni) throws SAXException {
- log.debug("Transforming element to sysview {}", ni.name);
-
- AttributesImpl attrs = new AttributesImpl();
-
- attrs.addAttribute(Name.NS_SV_URI, "name", "sv:name", "CDATA", ni.name);
- handler.startElement(Name.NS_SV_URI, "node", "sv:node", attrs);
-
- // add the properties
- for (DocViewProperty p: ni.props.values()) {
- if (p != null && p.values != null) {
- attrs = new AttributesImpl();
- attrs.addAttribute(Name.NS_SV_URI, "name", "sv:name", "CDATA", p.name);
- attrs.addAttribute(Name.NS_SV_URI, "type", "sv:type", "CDATA", PropertyType.nameFromValue(p.type));
- handler.startElement(Name.NS_SV_URI, "property", "sv:property", attrs);
- for (String v: p.values) {
- handler.startElement(Name.NS_SV_URI, "value", "sv:value", EMPTY_ATTRIBUTES);
- handler.characters(v.toCharArray(), 0, v.length());
- handler.endElement(Name.NS_SV_URI, "value", "sv:value");
- }
- handler.endElement(Name.NS_SV_URI, "property", "sv:property");
- }
- }
- }
-
- public void endNode() throws SAXException {
- handler.endElement(Name.NS_SV_URI, "node", "sv:node");
- }
- }
-
- /**
- * <code>DocViewNode</code>...
- */
- private static class DocViewNode {
-
- private final String name;
- private final String label;
- private final Map<String, DocViewProperty> props = new HashMap<String, DocViewProperty>();
- private String uuid = null;
- private String[] mixins = null;
- private String primary = null;
-
- public DocViewNode(String name, String label, Attributes attributes,
- NamePathResolver npResolver)
- throws NamespaceException {
- this.name = name;
- this.label = label;
- for (int i = 0; i < attributes.getLength(); i++) {
- // ignore non CDATA attributes
- if (!attributes.getType(i).equals("CDATA")) {
- continue;
- }
- Name pName = NameFactoryImpl.getInstance().create(
- attributes.getURI(i),
- ISO9075.decode(attributes.getLocalName(i)));
- DocViewProperty info = DocViewProperty.parse(
- npResolver.getJCRName(pName),
- attributes.getValue(i));
- props.put(info.name, info);
- if (pName.equals(NameConstants.JCR_UUID)) {
- uuid = info.values[0];
- } else if (pName.equals(NameConstants.JCR_PRIMARYTYPE)) {
- primary = info.values[0];
- } else if (pName.equals(NameConstants.JCR_MIXINTYPES)) {
- mixins = info.values;
- }
- }
- }
- }
}
Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/JackrabbitACLImporter.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/JackrabbitACLImporter.java?rev=1560258&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/JackrabbitACLImporter.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/JackrabbitACLImporter.java Wed Jan 22 05:49:45 2014
@@ -0,0 +1,256 @@
+/*************************************************************************
+ * 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.vault.fs.impl.io;
+
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Stack;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
+import javax.jcr.security.AccessControlEntry;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.AccessControlPolicy;
+import javax.jcr.security.AccessControlPolicyIterator;
+import javax.jcr.security.Privilege;
+
+import org.apache.jackrabbit.api.JackrabbitSession;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
+import org.apache.jackrabbit.api.security.principal.PrincipalManager;
+import org.apache.jackrabbit.vault.fs.io.AccessControlHandling;
+import org.apache.jackrabbit.vault.util.DocViewNode;
+import org.apache.jackrabbit.vault.util.DocViewProperty;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.SAXException;
+
+/**
+ * Implements a doc view adapter that reads the ACL information of the docview hierarchy and applies it to the
+ * underlying repository, based on the {@link org.apache.jackrabbit.vault.fs.io.AccessControlHandling}
+ */
+public class JackrabbitACLImporter implements DocViewAdapter {
+
+ /**
+ * default logger
+ */
+ private static final Logger log = LoggerFactory.getLogger(JackrabbitACLImporter.class);
+
+ private final Node accessControlledNode;
+
+ private final AccessControlHandling aclHandling;
+
+ private final AccessControlManager acMgr;
+
+ private final PrincipalManager pMgr;
+
+ private Map<String, List<ACE>> aceMap = new HashMap<String, List<ACE>>();
+
+ private ACE currentACE;
+
+ private static enum State {
+ INITIAL,
+ ACL,
+ ACE,
+ RESTRICTION,
+ ERROR,
+ }
+
+ private final Stack<State> states = new Stack<State>();
+
+ public JackrabbitACLImporter(Node accessControlledNode, AccessControlHandling aclHandling) throws RepositoryException {
+ if (aclHandling == AccessControlHandling.CLEAR || aclHandling == AccessControlHandling.IGNORE) {
+ throw new RepositoryException("Error while reading access control content: unsupported AccessControlHandling: " + aclHandling);
+ }
+ this.accessControlledNode = accessControlledNode;
+ this.acMgr = accessControlledNode.getSession().getAccessControlManager();
+ this.pMgr = ((JackrabbitSession) accessControlledNode.getSession()).getPrincipalManager();
+ this.aclHandling = aclHandling;
+ this.states.push(State.INITIAL);
+ }
+
+ public void startNode(DocViewNode node) throws SAXException {
+ State state = states.peek();
+ switch (state) {
+ case INITIAL:
+ if ("rep:ACL".equals(node.primary)) {
+ state = State.ACL;
+ } else {
+ log.error("Error while reading access control content: Expected rep:ACL but was: {}", node.primary);
+ state = State.ERROR;
+ }
+ break;
+
+ case ACL:
+ try {
+ currentACE = new ACE(node);
+ List<ACE> list = aceMap.get(currentACE.principalName);
+ if (list == null) {
+ list = new ArrayList<ACE>();
+ aceMap.put(currentACE.principalName, list);
+ }
+ list.add(currentACE);
+ state = State.ACE;
+ } catch (IllegalArgumentException e) {
+ log.error("Error while reading access control content: {}", e);
+ state = State.ERROR;
+ }
+ break;
+ case ACE:
+ currentACE.addRestrictions(node);
+ state = State.RESTRICTION;
+ break;
+ case RESTRICTION:
+ log.error("Error while reading access control content: Unexpected node: {} for state {}", node.primary, state);
+ state = State.ERROR;
+ break;
+ case ERROR:
+ // stay in error
+ break;
+ }
+ states.push(state);
+ }
+
+ public void endNode() throws SAXException {
+ State state = states.pop();
+ if (state == State.ACE) {
+ currentACE = null;
+ }
+ }
+
+ public void close() throws SAXException {
+ if (states.peek() != State.INITIAL) {
+ log.error("Unexpected end state: {}", states.peek());
+ }
+ try {
+ apply();
+ } catch (RepositoryException e) {
+ log.error("Error while applying access control content.", e);
+ }
+ }
+
+ private void apply() throws RepositoryException {
+ final String path = accessControlledNode.getPath();
+ final ValueFactory valueFactory = accessControlledNode.getSession().getValueFactory();
+
+ // find principals of existing ACL
+ JackrabbitAccessControlList acl = null;
+ Set<String> existingPrincipals = new HashSet<String>();
+ for (AccessControlPolicy p: acMgr.getPolicies(path)) {
+ if (p instanceof JackrabbitAccessControlList) {
+ acl = (JackrabbitAccessControlList) p;
+ for (AccessControlEntry ace: acl.getAccessControlEntries()) {
+ existingPrincipals.add(ace.getPrincipal().getName());
+ }
+ }
+ }
+
+ // remove existing policy for 'overwrite'
+ if (aclHandling == AccessControlHandling.OVERWRITE && acl != null) {
+ acMgr.removePolicy(path, acl);
+ acl = null;
+ }
+
+ if (acl == null) {
+ AccessControlPolicyIterator iter = acMgr.getApplicablePolicies(path);
+ while (iter.hasNext()) {
+ AccessControlPolicy p = iter.nextAccessControlPolicy();
+ if (p instanceof JackrabbitAccessControlList) {
+ acl = (JackrabbitAccessControlList) p;
+ break;
+ }
+ }
+ }
+ if (acl == null) {
+ throw new RepositoryException("not JackrabbitAccessControlList applicable on " + path);
+ }
+
+ // apply ACEs of package
+ for (Map.Entry<String, List<ACE>> entry: aceMap.entrySet()) {
+ final String principalName = entry.getKey();
+ if (aclHandling == AccessControlHandling.MERGE_PRESERVE && existingPrincipals.contains(principalName)) {
+ // skip principal if it already has an ACL
+ continue;
+ }
+ Principal principal = pMgr.getPrincipal(principalName);
+ if (principal == null) {
+ principal = new Principal(){
+ public String getName() {
+ return principalName;
+ }
+ };
+ }
+
+ for (ACE ace: entry.getValue()) {
+ Privilege[] privileges = new Privilege[ace.privileges.length];
+ for (int i = 0; i < privileges.length; i++) {
+ privileges[i] = acMgr.privilegeFromName(ace.privileges[i]);
+ }
+ Map<String, Value> svRestrictions = new HashMap<String, Value>();
+ Map<String, Value[]> mvRestrictions = new HashMap<String, Value[]>();
+ for (String restName : acl.getRestrictionNames()) {
+ DocViewProperty restriction = ace.restrictions.get(restName);
+ if (restriction != null) {
+ Value[] values = new Value[restriction.values.length];
+ int type = acl.getRestrictionType(restName);
+ for (int i=0; i<values.length; i++) {
+ values[i] = valueFactory.createValue(restriction.values[i], type);
+ }
+ if (restriction.isMulti) {
+ mvRestrictions.put(restName, values);
+ } else {
+ svRestrictions.put(restName, values[0]);
+ }
+ }
+ }
+ acl.addEntry(principal, privileges, ace.allow, svRestrictions, mvRestrictions);
+ }
+ }
+ acMgr.setPolicy(path, acl);
+ }
+
+ private static class ACE {
+
+ private final boolean allow;
+ private final String principalName;
+ private final String[] privileges;
+ private final Map<String, DocViewProperty> restrictions = new HashMap<String, DocViewProperty>();
+
+ private ACE(DocViewNode node) {
+ if ("rep:GrantACE".equals(node.primary)) {
+ allow = true;
+ } else if ("rep:DenyACE".equals(node.primary)) {
+ allow = false;
+ } else {
+ throw new IllegalArgumentException("Unexpected node ACE type: " + node.primary);
+ }
+ principalName = node.getValue("rep:principalName");
+ privileges = node.getValues("rep:privileges");
+ addRestrictions(node);
+ }
+
+ public void addRestrictions(DocViewNode node) {
+ restrictions.putAll(node.props);
+ }
+ }
+}
\ No newline at end of file
Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/JcrSysViewTransformer.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/JcrSysViewTransformer.java?rev=1560258&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/JcrSysViewTransformer.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/JcrSysViewTransformer.java Wed Jan 22 05:49:45 2014
@@ -0,0 +1,90 @@
+/*************************************************************************
+ * 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.vault.fs.impl.io;
+
+import javax.jcr.ImportUUIDBehavior;
+import javax.jcr.Node;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.vault.util.DocViewNode;
+import org.apache.jackrabbit.vault.util.DocViewProperty;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+/**
+* {@code JcrSysViewTransformer} transforms a docview importer hierarchy to a jcr sysview one by translating the
+ * vault specific docview nodes and properties into SAX events for the JCR sysview import content handler.
+ *
+ * @see Session#getImportContentHandler(String, int)
+*/
+public class JcrSysViewTransformer implements DocViewAdapter {
+
+ /**
+ * sysview handler for special content
+ */
+ private ContentHandler handler;
+
+ JcrSysViewTransformer(Node node) throws RepositoryException, SAXException {
+ Session session = node.getSession();
+ handler = session.getImportContentHandler(
+ node.getPath(),
+ ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING);
+ // first define the current namespaces
+ String[] prefixes = session.getNamespacePrefixes();
+ handler.startDocument();
+ for (String prefix: prefixes) {
+ handler.startPrefixMapping(prefix, session.getNamespaceURI(prefix));
+ }
+ }
+
+ public void close() throws SAXException {
+ handler.endDocument();
+ }
+
+ public void startNode(DocViewNode ni) throws SAXException {
+ DocViewSAXImporter.log.debug("Transforming element to sysview {}", ni.name);
+
+ AttributesImpl attrs = new AttributesImpl();
+
+ attrs.addAttribute(Name.NS_SV_URI, "name", "sv:name", "CDATA", ni.name);
+ handler.startElement(Name.NS_SV_URI, "node", "sv:node", attrs);
+
+ // add the properties
+ for (DocViewProperty p: ni.props.values()) {
+ if (p != null && p.values != null) {
+ attrs = new AttributesImpl();
+ attrs.addAttribute(Name.NS_SV_URI, "name", "sv:name", "CDATA", p.name);
+ attrs.addAttribute(Name.NS_SV_URI, "type", "sv:type", "CDATA", PropertyType.nameFromValue(p.type));
+ handler.startElement(Name.NS_SV_URI, "property", "sv:property", attrs);
+ for (String v: p.values) {
+ handler.startElement(Name.NS_SV_URI, "value", "sv:value", DocViewSAXImporter.EMPTY_ATTRIBUTES);
+ handler.characters(v.toCharArray(), 0, v.length());
+ handler.endElement(Name.NS_SV_URI, "value", "sv:value");
+ }
+ handler.endElement(Name.NS_SV_URI, "property", "sv:property");
+ }
+ }
+ }
+
+ public void endNode() throws SAXException {
+ handler.endElement(Name.NS_SV_URI, "node", "sv:node");
+ }
+}
\ No newline at end of file
Modified: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/AccessControlHandling.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/AccessControlHandling.java?rev=1560258&r1=1560257&r2=1560258&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/AccessControlHandling.java (original)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/AccessControlHandling.java Wed Jan 22 05:49:45 2014
@@ -35,19 +35,64 @@ public enum AccessControlHandling {
OVERWRITE,
/**
- * Tries to merge access control provided with the package with the one on
- * the target.
+ * Merge access control provided with the package with the one in the
+ * content by replacing the access control entries of corresponding
+ * principals (i.e. package first). It never alters access control entries
+ * of principals not present in the package.
+ * <p/>
+ * Example:<br/>
*
- * This is currently not fully supported and behaves like {@link #OVERWRITE}
- * for existing ACLs. ACLs not in the package are retained.
+ * Content ACL:
+ * <pre>
+ * everyone, deny, jcr:all
+ * bob, allow, jcr:read
+ * bob, allow, jcr:write
+ * </pre>
+ *
+ * Package ACL:
+ * <pre>
+ * bob, deny, jcr:all
+ * alice, allow, jcr:read
+ * </pre>
+ *
+ * Result ACL:
+ * <pre>
+ * everyone, deny, jcr:all
+ * bob, deny, jcr:all
+ * alice, allow, jcr:read
+ * </pre>
*/
MERGE,
/**
- * Tries to merge access control in the content with the one provided by the package.
+ * Merge access control in the content with the one provided with the
+ * package by adding the access control entries of principals not present in the
+ * content (i.e. content first). It never alters access control entries already
+ * existing in the content.
+ *
+ * <p/>
+ * Example:<br/>
+ *
+ * Content ACL:
+ * <pre>
+ * everyone, deny, jcr:all
+ * bob, allow, jcr:read
+ * bob, allow, jcr:write
+ * </pre>
+ *
+ * Package ACL:
+ * <pre>
+ * bob, deny, jcr:all
+ * alice, allow, jcr:read
+ * </pre>
*
- * This is currently not fully supported and behaves like {@link #IGNORE}
- * for existing ACLs. ACLs not in the package are retained.
+ * Result ACL:
+ * <pre>
+ * everyone, deny, jcr:all
+ * bob, allow, jcr:read
+ * bob, allow, jcr:write
+ * alice, allow, jcr:read
+ * </pre>
*/
MERGE_PRESERVE,
Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewNode.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewNode.java?rev=1560258&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewNode.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewNode.java Wed Jan 22 05:49:45 2014
@@ -0,0 +1,87 @@
+/*************************************************************************
+ * 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.vault.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jcr.NamespaceException;
+import javax.jcr.Value;
+
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
+import org.apache.jackrabbit.spi.commons.name.NameConstants;
+import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
+import org.apache.jackrabbit.util.ISO9075;
+import org.xml.sax.Attributes;
+
+/**
+ * Helper class that represents a (jcr) node abstraction based on
+ * {@link org.apache.jackrabbit.vault.util.DocViewProperty properties}.
+ */
+public class DocViewNode {
+
+ public final String name;
+ public final String label;
+ public final Map<String, DocViewProperty> props = new HashMap<String, DocViewProperty>();
+ public String uuid;
+ public final String[] mixins;
+ public final String primary;
+
+ public DocViewNode(String name, String label, Attributes attributes, NamePathResolver npResolver)
+ throws NamespaceException {
+ this.name = name;
+ this.label = label;
+ String uuid = null;
+ String primary = null;
+ String[] mixins = null;
+ for (int i = 0; i < attributes.getLength(); i++) {
+ // ignore non CDATA attributes
+ if (!attributes.getType(i).equals("CDATA")) {
+ continue;
+ }
+ Name pName = NameFactoryImpl.getInstance().create(
+ attributes.getURI(i),
+ ISO9075.decode(attributes.getLocalName(i)));
+ DocViewProperty info = DocViewProperty.parse(
+ npResolver.getJCRName(pName),
+ attributes.getValue(i));
+ props.put(info.name, info);
+ if (pName.equals(NameConstants.JCR_UUID)) {
+ uuid = info.values[0];
+ } else if (pName.equals(NameConstants.JCR_PRIMARYTYPE)) {
+ primary = info.values[0];
+ } else if (pName.equals(NameConstants.JCR_MIXINTYPES)) {
+ mixins = info.values;
+ }
+ }
+ this.uuid = uuid;
+ this.mixins = mixins;
+ this.primary = primary;
+ }
+
+ public String[] getValues(String name) {
+ DocViewProperty prop = props.get(name);
+ return prop == null ? null : prop.values;
+ }
+
+ public String getValue(String name) {
+ DocViewProperty prop = props.get(name);
+ return prop == null ? null : prop.values[0];
+ }
+
+}
\ No newline at end of file
Modified: jackrabbit/commons/filevault/trunk/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/IntegrationTestBase.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/IntegrationTestBase.java?rev=1560258&r1=1560257&r2=1560258&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/IntegrationTestBase.java (original)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/IntegrationTestBase.java Wed Jan 22 05:49:45 2014
@@ -80,7 +80,7 @@ public class IntegrationTestBase {
@BeforeClass
public static void initRepository() throws RepositoryException {
- if (Boolean.getBoolean("oak")) {
+ if (isOak()) {
Properties userProps = new Properties();
userProps.put(UserConstants.PARAM_USER_PATH, "/home/users");
userProps.put(UserConstants.PARAM_GROUP_PATH, "/home/groups");
@@ -128,6 +128,10 @@ public class IntegrationTestBase {
packMgr = new JcrPackageManagerImpl(admin);
}
+ public static boolean isOak() {
+ return Boolean.getBoolean("oak");
+ }
+
public void clean(String path) {
try {
admin.getNode(path).remove();
Modified: jackrabbit/commons/filevault/trunk/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/TestACLAndMerge.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/TestACLAndMerge.java?rev=1560258&r1=1560257&r2=1560258&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/TestACLAndMerge.java (original)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/TestACLAndMerge.java Wed Jan 22 05:49:45 2014
@@ -19,21 +19,31 @@ package org.apache.jackrabbit.vault.pack
import java.io.IOException;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.Map;
import java.util.Set;
import javax.jcr.RepositoryException;
+import javax.jcr.Value;
import javax.jcr.security.AccessControlEntry;
import javax.jcr.security.AccessControlPolicy;
import javax.jcr.security.Privilege;
+import org.apache.jackrabbit.api.JackrabbitSession;
import org.apache.jackrabbit.api.security.JackrabbitAccessControlEntry;
import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.jackrabbit.vault.fs.io.AccessControlHandling;
+import org.apache.jackrabbit.vault.fs.io.ImportOptions;
import org.apache.jackrabbit.vault.packaging.JcrPackage;
import org.apache.jackrabbit.vault.packaging.PackageException;
+import org.junit.Assume;
import org.junit.Test;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
@@ -41,6 +51,18 @@ import static org.junit.Assert.fail;
*/
public class TestACLAndMerge extends IntegrationTestBase {
+ private final static String NAME_TEST_USER = "testuser";
+
+ private UserManager uMgr;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ uMgr = ((JackrabbitSession) admin).getUserManager();
+ uMgr.createUser(NAME_TEST_USER, "test");
+ admin.save();
+ }
+
@Override
public void tearDown() throws Exception {
// remove test node
@@ -48,6 +70,13 @@ public class TestACLAndMerge extends Int
admin.getNode("/testroot").remove();
admin.save();
}
+ try {
+ Authorizable testUser = uMgr.getAuthorizable(NAME_TEST_USER);
+ testUser.remove();
+ admin.save();
+ } catch (RepositoryException e) {
+ // ignore
+ }
super.tearDown();
}
@@ -104,11 +133,95 @@ public class TestACLAndMerge extends Int
assertNodeExists("/testroot/node_b");
assertPermission("/testroot/secured", false, new String[]{"jcr:all"}, "everyone", null);
assertPermission("/testroot/secured", true, new String[]{"jcr:read"}, "everyone", "*/foo/*");
+ }
+ /**
+ * Installs 2 packages with ACL for different principals. the first package has an ace for 'everyone' the 2nd for
+ * 'testuser'. the later package should not corrupt the existing acl (unlike overwrite).
+ */
+ @Test
+ public void testACMerge2() throws RepositoryException, IOException, PackageException {
+ assertNodeMissing("/testroot");
+
+ JcrPackage pack = packMgr.upload(getStream("testpackages/mode_ac_test_a.zip"), false);
+ assertNotNull(pack);
+ pack.install(getDefaultOptions());
+
+ // test if nodes and ACLs of first package exist
+ assertNodeExists("/testroot/node_a");
+ assertPermission("/testroot/secured", false, new String[]{"jcr:all"}, "everyone", null);
+
+ pack = packMgr.upload(getStream("testpackages/mode_ac_test_c_merge.zip"), false);
+ assertNotNull(pack);
+ pack.install(getDefaultOptions());
+
+ // test if nodes and ACLs of 2nd package exist
+ assertNodeExists("/testroot/node_a");
+ assertNodeExists("/testroot/node_c");
+ assertPermission("/testroot/secured", false, new String[]{"jcr:all"}, "everyone", null);
+ assertPermission("/testroot/secured", true, new String[]{"jcr:all"}, "testuser", null);
}
/**
- * Installs 2 packages with the same ACL. the later packages has AC Handling MERGE_PRESERVER and should
+ * Installs 2 packages with ACL for different principals. the first package has an ace for 'everyone' the 2nd for
+ * 'everyone' and 'testuser'. merge mode should overwrite the 'everyone' ACE.
+ */
+ @Test
+ public void testACMerge3() throws RepositoryException, IOException, PackageException {
+ assertNodeMissing("/testroot");
+
+ JcrPackage pack = packMgr.upload(getStream("testpackages/mode_ac_test_a.zip"), false);
+ assertNotNull(pack);
+ pack.install(getDefaultOptions());
+
+ // test if nodes and ACLs of first package exist
+ assertNodeExists("/testroot/node_a");
+ assertPermission("/testroot/secured", false, new String[]{"jcr:all"}, "everyone", null);
+
+ pack = packMgr.upload(getStream("testpackages/mode_ac_test_d.zip"), false);
+ assertNotNull(pack);
+ pack.install(getDefaultOptions());
+
+ // test if nodes and ACLs of 2nd package exist
+ assertNodeExists("/testroot/node_a");
+ assertNodeExists("/testroot/node_d");
+ assertPermission("/testroot/secured", true, new String[]{"jcr:all"}, "everyone", null);
+ assertPermission("/testroot/secured", true, new String[]{"jcr:all"}, "testuser", null);
+ }
+
+ /**
+ * Installs 2 packages with ACL for different principals. the first package has an ace for 'everyone' the 2nd for
+ * 'everyone' and 'testuser'. merge_preserve mode should NOT overwrite the 'everyone' ACE.
+ */
+ @Test
+ public void testACMergePreserve2() throws RepositoryException, IOException, PackageException {
+ assertNodeMissing("/testroot");
+
+ JcrPackage pack = packMgr.upload(getStream("testpackages/mode_ac_test_a.zip"), false);
+ assertNotNull(pack);
+ pack.install(getDefaultOptions());
+
+ // test if nodes and ACLs of first package exist
+ assertNodeExists("/testroot/node_a");
+ assertPermission("/testroot/secured", false, new String[]{"jcr:all"}, "everyone", null);
+
+ pack = packMgr.upload(getStream("testpackages/mode_ac_test_d.zip"), false);
+ assertNotNull(pack);
+ ImportOptions opts = getDefaultOptions();
+ opts.setAccessControlHandling(AccessControlHandling.MERGE_PRESERVE);
+ pack.install(opts);
+
+ // test if nodes and ACLs of 2nd package exist
+ assertNodeExists("/testroot/node_a");
+ assertNodeExists("/testroot/node_d");
+ assertPermission("/testroot/secured", false, new String[]{"jcr:all"}, "everyone", null);
+ assertPermission("/testroot/secured", true, new String[]{"jcr:all"}, "testuser", null);
+ }
+
+
+
+ /**
+ * Installs 2 packages with the same ACL. the later packages has AC Handling MERGE_PRESERVE and should
* retain the existing ACL.
*/
@Test
@@ -135,21 +248,53 @@ public class TestACLAndMerge extends Int
}
+ /**
+ * Installs a package with oak ACL content.
+ */
+ @Test
+ public void testOakContent() throws RepositoryException, IOException, PackageException {
+ Assume.assumeTrue(isOak());
+ assertNodeMissing("/testroot");
+
+ JcrPackage pack = packMgr.upload(getStream("testpackages/oak_ac_content_test.zip"), false);
+ assertNotNull(pack);
+ pack.install(getDefaultOptions());
+
+ // test if nodes and ACLs of first package exist
+ assertNodeExists("/testroot/node_a");
+ Map<String, String[]> restrictions = new HashMap<String, String[]>();
+ restrictions.put("rep:glob", new String[]{"*/foo"});
+ restrictions.put("rep:ntNames", new String[]{"nt:unstructured"});
+ restrictions.put("rep:prefixes", new String[]{"rep", "granite"});
+ assertTrue(
+ "expected permission missing",
+ hasPermission("/testroot/secured", true, new String[]{"jcr:all"}, "everyone", restrictions)
+ );
+ }
+
protected void assertPermissionMissing(String path, boolean allow, String[] privs, String name, String globRest)
throws RepositoryException {
- if (hasPermission(path, allow, privs, name, globRest)) {
+ Map<String, String[]> restrictions = new HashMap<String, String[]>();
+ if (globRest != null) {
+ restrictions.put("rep:glob", new String[]{globRest});
+ }
+ if (hasPermission(path, allow, privs, name, restrictions)) {
fail("Expected permission should not exist on path " + path);
}
}
protected void assertPermission(String path, boolean allow, String[] privs, String name, String globRest)
throws RepositoryException {
- if (!hasPermission(path, allow, privs, name, globRest)) {
+ Map<String, String[]> restrictions = new HashMap<String, String[]>();
+ if (globRest != null) {
+ restrictions.put("rep:glob", new String[]{globRest});
+ }
+ if (!hasPermission(path, allow, privs, name, restrictions)) {
fail("Expected permission missing on path " + path);
}
}
- protected boolean hasPermission(String path, boolean allow, String[] privs, String name, String globRest)
+ protected boolean hasPermission(String path, boolean allow, String[] privs, String name, Map<String, String[]> restrictions)
throws RepositoryException {
AccessControlPolicy[] ap = admin.getAccessControlManager().getPolicies(path);
boolean found = false;
@@ -175,7 +320,31 @@ public class TestACLAndMerge extends Int
if (!expectedPrivs.isEmpty()) {
continue;
}
- if (globRest != null && !globRest.equals(ace.getRestriction("rep:glob").getString())) {
+ Map<String, String[]> rests = new HashMap<String, String[]>(restrictions);
+ boolean restrictionExpected = true;
+ for (String restName: ace.getRestrictionNames()) {
+ String[] expected = rests.remove(restName);
+ if (expected == null) {
+ continue;
+ }
+ Value[] values;
+ if ("rep:glob".equals(restName)) {
+ values = new Value[]{ace.getRestriction(restName)};
+ } else {
+ values = ace.getRestrictions(restName);
+ }
+ String[] actual = new String[values.length];
+ for (int i=0; i<actual.length; i++) {
+ actual[i] = values[i].getString();
+ }
+ Arrays.sort(expected);
+ Arrays.sort(actual);
+ if (!Arrays.equals(expected, actual)) {
+ restrictionExpected = false;
+ break;
+ }
+ }
+ if (!restrictionExpected || !rests.isEmpty()) {
continue;
}
found = true;
Added: jackrabbit/commons/filevault/trunk/vault-core/src/test/resources/org/apache/jackrabbit/vault/packaging/integration/testpackages/mode_ac_test_c_merge.zip
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/test/resources/org/apache/jackrabbit/vault/packaging/integration/testpackages/mode_ac_test_c_merge.zip?rev=1560258&view=auto
==============================================================================
Binary file - no diff available.
Propchange: jackrabbit/commons/filevault/trunk/vault-core/src/test/resources/org/apache/jackrabbit/vault/packaging/integration/testpackages/mode_ac_test_c_merge.zip
------------------------------------------------------------------------------
svn:mime-type = application/jar
Added: jackrabbit/commons/filevault/trunk/vault-core/src/test/resources/org/apache/jackrabbit/vault/packaging/integration/testpackages/mode_ac_test_d.zip
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/test/resources/org/apache/jackrabbit/vault/packaging/integration/testpackages/mode_ac_test_d.zip?rev=1560258&view=auto
==============================================================================
Binary file - no diff available.
Propchange: jackrabbit/commons/filevault/trunk/vault-core/src/test/resources/org/apache/jackrabbit/vault/packaging/integration/testpackages/mode_ac_test_d.zip
------------------------------------------------------------------------------
svn:mime-type = application/jar
Added: jackrabbit/commons/filevault/trunk/vault-core/src/test/resources/org/apache/jackrabbit/vault/packaging/integration/testpackages/oak_ac_content_test.zip
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/test/resources/org/apache/jackrabbit/vault/packaging/integration/testpackages/oak_ac_content_test.zip?rev=1560258&view=auto
==============================================================================
Binary file - no diff available.
Propchange: jackrabbit/commons/filevault/trunk/vault-core/src/test/resources/org/apache/jackrabbit/vault/packaging/integration/testpackages/oak_ac_content_test.zip
------------------------------------------------------------------------------
svn:mime-type = application/jar