Author: angela Date: Mon Mar 14 16:00:40 2011 New Revision: 1081433 URL: http://svn.apache.org/viewvc?rev=1081433&view=rev Log: JCR-2887 : Split PrivilegeRegistry in a per-session manager instance and a repository level registry [work in progress] Added: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/ jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/ParseException.java (with props) jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeDefinition.java (with props) jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeDefinitionReader.java (with props) jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeDefinitionWriter.java (with props) jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeHandler.java (with props) jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeXmlHandler.java (with props) Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/PrivilegeManagerImpl.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/PrivilegeRegistry.java jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/PrivilegeRegistryTest.java Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/PrivilegeManagerImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/PrivilegeManagerImpl.java?rev=1081433&r1=1081432&r2=1081433&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/PrivilegeManagerImpl.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/PrivilegeManagerImpl.java Mon Mar 14 16:00:40 2011 @@ -84,10 +84,10 @@ public final class PrivilegeManagerImpl * @return all registered privileges. */ public Privilege[] getRegisteredPrivileges() throws RepositoryException { - PrivilegeRegistry.PrivilegeDefinition[] allDefs = registry.getAll(); + PrivilegeRegistry.Definition[] allDefs = registry.getAll(); if (allDefs.length != cache.size()) { synchronized (cache) { - for (PrivilegeRegistry.PrivilegeDefinition def : allDefs) { + for (PrivilegeRegistry.Definition def : allDefs) { if (!cache.containsKey(def.getName())) { cache.put(def.getName(), new PrivilegeImpl(def)); } @@ -204,7 +204,7 @@ public final class PrivilegeManagerImpl int bits = PrivilegeRegistry.NO_PRIVILEGE; for (String privName : privilegeNames) { try { - PrivilegeRegistry.PrivilegeDefinition def = registry.get(resolver.getQName(privName)); + PrivilegeRegistry.Definition def = registry.get(resolver.getQName(privName)); if (def == null) { throw new AccessControlException("Unknown privilege name '" + privName + "'."); } else { @@ -257,7 +257,7 @@ public final class PrivilegeManagerImpl if (cache.containsKey(name)) { privilege = cache.get(name); } else { - PrivilegeRegistry.PrivilegeDefinition def = registry.get(name); + PrivilegeRegistry.Definition def = registry.get(name); if (def != null) { privilege = new PrivilegeImpl(def); cache.put(name, privilege); @@ -288,12 +288,12 @@ public final class PrivilegeManagerImpl */ private class PrivilegeImpl implements Privilege { - private final PrivilegeRegistry.PrivilegeDefinition definition; + private final PrivilegeRegistry.Definition definition; private final Privilege[] declaredAggregates; private final Privilege[] aggregates; - private PrivilegeImpl(PrivilegeRegistry.PrivilegeDefinition definition) throws RepositoryException { + private PrivilegeImpl(PrivilegeRegistry.Definition definition) throws RepositoryException { this.definition = definition; Name[] aggrNames = definition.getDeclaredAggregateNames(); Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/PrivilegeRegistry.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/PrivilegeRegistry.java?rev=1081433&r1=1081432&r2=1081433&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/PrivilegeRegistry.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/PrivilegeRegistry.java Mon Mar 14 16:00:40 2011 @@ -17,6 +17,10 @@ package org.apache.jackrabbit.core.security.authorization; import org.apache.commons.collections.map.ReferenceMap; +import org.apache.jackrabbit.commons.privilege.ParseException; +import org.apache.jackrabbit.commons.privilege.PrivilegeDefinition; +import org.apache.jackrabbit.commons.privilege.PrivilegeDefinitionReader; +import org.apache.jackrabbit.commons.privilege.PrivilegeDefinitionWriter; import org.apache.jackrabbit.core.NamespaceRegistryImpl; import org.apache.jackrabbit.core.fs.FileSystem; import org.apache.jackrabbit.core.fs.FileSystemException; @@ -35,16 +39,17 @@ import javax.jcr.NamespaceRegistry; import javax.jcr.RepositoryException; import javax.jcr.security.AccessControlException; import javax.jcr.security.Privilege; -import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.Writer; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.Set; @@ -106,7 +111,7 @@ public final class PrivilegeRegistry { private static final String CUSTOM_PRIVILEGES_RESOURCE_NAME = "/privileges/custom_privileges.xml"; - private final Map registeredPrivileges = new HashMap(); + private final Map registeredPrivileges = new HashMap(); private final Map> bitsToNames = new HashMap>(); @SuppressWarnings("unchecked") @@ -115,9 +120,6 @@ public final class PrivilegeRegistry { private final NamespaceRegistry namespaceRegistry; private final CustomPrivilegeStore customPrivilegesStore; - /** - * @deprecated For backwards compatibility only. - */ private final NameResolver resolver; private int nextBits = RETENTION_MNGMT << 1; @@ -131,12 +133,14 @@ public final class PrivilegeRegistry { try { Map customDefs = customPrivilegesStore.load(); - Map definitions = createPrivilegeDefinitions(customDefs); + Map definitions = createPrivilegeDefinitions(customDefs); registerDefinitions(definitions); } catch (IOException e) { throw new RepositoryException("Failed to load custom privileges", e); } catch (FileSystemException e) { throw new RepositoryException("Failed to load custom privileges", e); + } catch (ParseException e) { + throw new RepositoryException("Failed to load custom privileges", e); } this.resolver = new DefaultNamePathResolver(namespaceRegistry); @@ -234,7 +238,7 @@ public final class PrivilegeRegistry { } else if (NameConstants.JCR_WRITE.equals(n)) { bits |= createJcrWriteDefinition().bits; } else if (REP_WRITE_NAME.equals(n)) { - PrivilegeDefinition jcrWrite = createJcrWriteDefinition(); + Definition jcrWrite = createJcrWriteDefinition(); bits |= createRepWriteDefinition(jcrWrite.bits).bits; } else if (NameConstants.JCR_ALL.equals(n)) { for (Name pn : PRIVILEGE_NAMES.keySet()) { @@ -371,7 +375,7 @@ public final class PrivilegeRegistry { } synchronized (registeredPrivileges) { Map stubs = Collections.singletonMap(privilegeName, new DefinitionStub(privilegeName, isAbstract, declaredAggregateNames, true)); - Map definitions = createPrivilegeDefinitions(stubs); + Map definitions = createPrivilegeDefinitions(stubs); try { // write the new custom privilege to the store and upon successful // update of the file system resource add finally it to the map of @@ -383,6 +387,8 @@ public final class PrivilegeRegistry { throw new RepositoryException("Failed to register custom privilege " + privilegeName.toString(), e); } catch (FileSystemException e) { throw new RepositoryException("Failed to register custom privilege " + privilegeName.toString(), e); + } catch (ParseException e) { + throw new RepositoryException("Failed to register custom privilege " + privilegeName.toString(), e); } } @@ -396,8 +402,8 @@ public final class PrivilegeRegistry { * * @return all registered internal privileges */ - PrivilegeDefinition[] getAll() { - return registeredPrivileges.values().toArray(new PrivilegeDefinition[registeredPrivileges.size()]); + Definition[] getAll() { + return registeredPrivileges.values().toArray(new Definition[registeredPrivileges.size()]); } /** @@ -406,7 +412,7 @@ public final class PrivilegeRegistry { * @param name Name of the internal privilege. * @return the internal privilege with the specified name or null */ - PrivilegeDefinition get(Name name) { + Definition get(Name name) { return registeredPrivileges.get(name); } @@ -466,7 +472,7 @@ public final class PrivilegeRegistry { } // include matching custom privilege names - for (PrivilegeDefinition def : registeredPrivileges.values()) { + for (Definition def : registeredPrivileges.values()) { if (def.isCustom && ((bits & def.bits) == def.bits)) { names.add(def.name); } @@ -490,25 +496,25 @@ public final class PrivilegeRegistry { * * @param definitions */ - private void registerDefinitions(Map definitions) { + private void registerDefinitions(Map definitions) { registeredPrivileges.putAll(definitions); - for (PrivilegeDefinition def : definitions.values()) { + for (Definition def : definitions.values()) { bitsToNames.put(def.bits, Collections.singleton(def.name)); } if (!definitions.containsKey(NameConstants.JCR_ALL)) { // redefine the jcr:all privilege definition - PrivilegeDefinition all = registeredPrivileges.get(NameConstants.JCR_ALL); + Definition all = registeredPrivileges.get(NameConstants.JCR_ALL); Set allAggrNames = all.declaredAggregateNames; allAggrNames.addAll(definitions.keySet()); int allBits = all.bits; - for (PrivilegeDefinition def : definitions.values()) { + for (Definition def : definitions.values()) { allBits |= def.bits; } - all = new PrivilegeDefinition(NameConstants.JCR_ALL, false, allAggrNames, allBits); + all = new Definition(NameConstants.JCR_ALL, false, allAggrNames, allBits); registeredPrivileges.put(NameConstants.JCR_ALL, all); bitsToNames.put(all.bits, Collections.singleton(NameConstants.JCR_ALL)); } @@ -519,24 +525,24 @@ public final class PrivilegeRegistry { * * @return definitions for all built-in privileges. */ - private Map createBuiltInPrivilegeDefinitions() { - Map defs = new HashMap(); + private Map createBuiltInPrivilegeDefinitions() { + Map defs = new HashMap(); // all non-aggregate privileges int jcrAllBits = NO_PRIVILEGE; for (Name privilegeName : PRIVILEGE_NAMES.keySet()) { int bits = PRIVILEGE_NAMES.get(privilegeName); - PrivilegeDefinition def = new PrivilegeDefinition(privilegeName, false, bits); + Definition def = new Definition(privilegeName, false, bits); defs.put(privilegeName, def); jcrAllBits |= bits; } // jcr:write - PrivilegeDefinition jcrWrite = createJcrWriteDefinition(); + Definition jcrWrite = createJcrWriteDefinition(); defs.put(jcrWrite.name, jcrWrite); // rep:write - PrivilegeDefinition repWrite = createRepWriteDefinition(jcrWrite.bits); + Definition repWrite = createRepWriteDefinition(jcrWrite.bits); defs.put(repWrite.name, repWrite); // jcr:all @@ -552,7 +558,7 @@ public final class PrivilegeRegistry { jcrAllAggregates.add(NameConstants.JCR_WRITE); jcrAllAggregates.add(REP_WRITE_NAME); - PrivilegeDefinition jcrAll = new PrivilegeDefinition(NameConstants.JCR_ALL, false, jcrAllAggregates, jcrAllBits); + Definition jcrAll = new Definition(NameConstants.JCR_ALL, false, jcrAllAggregates, jcrAllBits); defs.put(jcrAll.name, jcrAll); return defs; @@ -568,8 +574,8 @@ public final class PrivilegeRegistry { * @return new privilege definitions. * @throws RepositoryException If any of the specified stubs is invalid. */ - private Map createPrivilegeDefinitions(Map toRegister) throws RepositoryException { - Map definitions = new HashMap(toRegister.size()); + private Map createPrivilegeDefinitions(Map toRegister) throws RepositoryException { + Map definitions = new HashMap(toRegister.size()); Set aggregates = new HashSet(); for (DefinitionStub stub : toRegister.values()) { @@ -592,7 +598,7 @@ public final class PrivilegeRegistry { // validate aggregates if (stub.declaredAggregateNames.isEmpty()) { // not an aggregate priv definition. - definitions.put(name, new PrivilegeDefinition(stub, nextBits())); + definitions.put(name, new Definition(stub, nextBits())); } else { for (Name declaredAggregateName : stub.declaredAggregateNames) { if (name.equals(declaredAggregateName)) { @@ -629,7 +635,7 @@ public final class PrivilegeRegistry { throw new RepositoryException("Custom aggregate privilege '" + stub.name + "' is already covered by '" + existingName.toString() + "'"); } if (bts != NO_PRIVILEGE) { - PrivilegeDefinition def = new PrivilegeDefinition(stub, bts); + Definition def = new Definition(stub, bts); definitions.put(def.name, def); itr.remove(); } @@ -660,13 +666,13 @@ public final class PrivilegeRegistry { * @param toRegister * @return */ - private int getAggregateBits(Set declaredAggregateNames, Map toRegister) { + private int getAggregateBits(Set declaredAggregateNames, Map toRegister) { int bts = NO_PRIVILEGE; for (Name n : declaredAggregateNames) { if (registeredPrivileges.containsKey(n)) { bts |= registeredPrivileges.get(n).bits; } else if (toRegister.containsKey(n)) { - PrivilegeDefinition def = toRegister.get(n); + Definition def = toRegister.get(n); if (def.bits == NO_PRIVILEGE) { // not yet processed dependency -> wait for next iteration. return NO_PRIVILEGE; @@ -709,7 +715,7 @@ public final class PrivilegeRegistry { /** * @return PrivilegeDefinition for the jcr:write privilege */ - private static PrivilegeDefinition createJcrWriteDefinition() { + private static Definition createJcrWriteDefinition() { Set jcrWriteAggregates = new HashSet(4); jcrWriteAggregates.add(NameConstants.JCR_MODIFY_PROPERTIES); jcrWriteAggregates.add(NameConstants.JCR_ADD_CHILD_NODES); @@ -720,16 +726,16 @@ public final class PrivilegeRegistry { for (Name privilegeName : jcrWriteAggregates) { jcrWriteBits |= PRIVILEGE_NAMES.get(privilegeName); } - return new PrivilegeDefinition(NameConstants.JCR_WRITE, false, jcrWriteAggregates, jcrWriteBits); + return new Definition(NameConstants.JCR_WRITE, false, jcrWriteAggregates, jcrWriteBits); } - private static PrivilegeDefinition createRepWriteDefinition(int jcrWriteBits) { + private static Definition createRepWriteDefinition(int jcrWriteBits) { Set repWriteAggregates = new HashSet(2); repWriteAggregates.add(NameConstants.JCR_WRITE); repWriteAggregates.add(NameConstants.JCR_NODE_TYPE_MANAGEMENT); int repWriteBits = jcrWriteBits | PRIVILEGE_NAMES.get(NameConstants.JCR_NODE_TYPE_MANAGEMENT); - return new PrivilegeDefinition(REP_WRITE_NAME, false, repWriteAggregates, repWriteBits); + return new Definition(REP_WRITE_NAME, false, repWriteAggregates, repWriteBits); } //-------------------------------------------------------------------------- @@ -799,23 +805,23 @@ public final class PrivilegeRegistry { /** * Internal definition of a jcr level privilege. */ - static class PrivilegeDefinition extends DefinitionStub { + static class Definition extends DefinitionStub { private final int bits; - private PrivilegeDefinition(DefinitionStub stub, int bits) { + private Definition(DefinitionStub stub, int bits) { this(stub.name, stub.isAbstract, stub.declaredAggregateNames, bits, stub.isCustom); } - private PrivilegeDefinition(Name name, boolean isAbstract, int bits) { + private Definition(Name name, boolean isAbstract, int bits) { this(name, isAbstract, Collections.emptySet(), bits, false); } - private PrivilegeDefinition(Name name, boolean isAbstract, Set declaredAggregateNames, int bits) { + private Definition(Name name, boolean isAbstract, Set declaredAggregateNames, int bits) { this(name, isAbstract, declaredAggregateNames, bits, false); } - private PrivilegeDefinition(Name name, boolean isAbstract, Set declaredAggregateNames, int bits, boolean isCustom) { + private Definition(Name name, boolean isAbstract, Set declaredAggregateNames, int bits, boolean isCustom) { super(name, isAbstract, declaredAggregateNames, isCustom); if (bits == NO_PRIVILEGE) { throw new IllegalArgumentException("Failed to build int representation of PrivilegeDefinition."); @@ -871,76 +877,79 @@ public final class PrivilegeRegistry { } } - private Map load() throws IOException, FileSystemException, RepositoryException { + private Map load() throws FileSystemException, RepositoryException, ParseException, IOException { Map stubs = new LinkedHashMap(); if (customPrivilegesResource.exists()) { - BufferedReader reader = new BufferedReader(new InputStreamReader(customPrivilegesResource.getInputStream(), "utf-8")); + InputStream in = customPrivilegesResource.getInputStream(); try { - String line; - while ((line = reader.readLine()) != null) { - String[] params = Text.explode(line, ';', true); - - if (params.length < 1) { - // empty line - continue; - } + PrivilegeDefinitionReader pr = new PrivilegeDefinitionReader(in, "text/xml"); + for (PrivilegeDefinition def : pr.getPrivilegeDefinitions()) { - Name privName = NAME_FACTORY.create(params[0]); - boolean isAbstract = false; + Name privName = getName(def.getName()); + boolean isAbstract = def.isAbstract(); Set declaredAggrNames = new HashSet(); - - if (params.length >= 2) { - isAbstract = "abstract".equals(params[1]); - } - if (params.length >= 3) { - String[] declExpNames = Text.explode(params[2], ','); - for (String declExpName : declExpNames) { - declaredAggrNames.add(NAME_FACTORY.create(declExpName)); - } + for (String dan : def.getDeclaredAggregateNames()) { + declaredAggrNames.add(getName(dan)); } if (stubs.containsKey(privName)) { throw new RepositoryException("Duplicate entry for custom privilege with name " + privName.toString()); } stubs.put(privName, new DefinitionStub(privName, isAbstract, declaredAggrNames, true)); - } } finally { - reader.close(); + in.close(); } } return stubs; } - private void append(Map newPrivilegeDefinitions) throws IOException, FileSystemException, RepositoryException { - Map defs = load(); - defs.putAll(newPrivilegeDefinitions); + private Name getName(String jcrName) throws RepositoryException { + String uri = namespaceRegistry.getURI(Text.getNamespacePrefix(jcrName)); + return NAME_FACTORY.create(uri, Text.getLocalName(jcrName)); + } - Writer writer = new OutputStreamWriter(customPrivilegesResource.getOutputStream(), "utf-8"); - try { - for (DefinitionStub def : defs.values()) { - StringBuilder sb = new StringBuilder(); - sb.append(def.name.toString()).append(';'); - if (def.isAbstract) { - sb.append("abstract"); - } - sb.append(";"); - if (!def.declaredAggregateNames.isEmpty()) { - int cnt = 0; - for (Name dan : def.declaredAggregateNames) { - if (cnt > 0) { - sb.append(","); - } - sb.append(dan.toString()); - cnt++; - } - } - writer.write(sb.toString()); - writer.write("\n"); + private void append(Map newPrivilegeDefinitions) throws IOException, FileSystemException, RepositoryException, ParseException { + List jcrDefs; + Map nsMapping; + + if (customPrivilegesResource.exists()) { + InputStream in = customPrivilegesResource.getInputStream(); + try { + PrivilegeDefinitionReader pr = new PrivilegeDefinitionReader(in, "text/xml"); + jcrDefs = new ArrayList(Arrays.asList(pr.getPrivilegeDefinitions())); + nsMapping = pr.getNamespaces(); + } finally { + in.close(); + } + } else { + jcrDefs = new ArrayList(); + nsMapping = new HashMap(); + } + + for (Definition d : newPrivilegeDefinitions.values()) { + String name = resolver.getJCRName(d.name); + String uri = d.name.getNamespaceURI(); + nsMapping.put(namespaceRegistry.getPrefix(uri), uri); + + String[] aggrNames = new String[d.declaredAggregateNames.size()]; + int i = 0; + for (Name dan : d.declaredAggregateNames) { + aggrNames[i++] = resolver.getJCRName(dan); + uri = d.name.getNamespaceURI(); + nsMapping.put(namespaceRegistry.getPrefix(uri), uri); } + PrivilegeDefinition pd = new PrivilegeDefinition(name, d.isAbstract, aggrNames); + jcrDefs.add(pd); + } + + OutputStream out = customPrivilegesResource.getOutputStream(); + try { + PrivilegeDefinitionWriter pdw = new PrivilegeDefinitionWriter("text/xml"); + pdw.writeDefinitions(out, jcrDefs.toArray(new PrivilegeDefinition[jcrDefs.size()]), nsMapping); } finally { - writer.close(); + out.close(); } } } Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/PrivilegeRegistryTest.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/PrivilegeRegistryTest.java?rev=1081433&r1=1081432&r2=1081433&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/PrivilegeRegistryTest.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/PrivilegeRegistryTest.java Mon Mar 14 16:00:40 2011 @@ -27,7 +27,6 @@ import org.apache.jackrabbit.spi.commons import org.apache.jackrabbit.spi.commons.name.NameConstants; import org.apache.jackrabbit.test.AbstractJCRTest; -import javax.jcr.NamespaceException; import javax.jcr.RepositoryException; import javax.jcr.security.AccessControlException; import javax.jcr.security.Privilege; @@ -60,9 +59,9 @@ public class PrivilegeRegistryTest exten public void testGetAll() throws RepositoryException { - PrivilegeRegistry.PrivilegeDefinition[] defs = privilegeRegistry.getAll(); + PrivilegeRegistry.Definition[] defs = privilegeRegistry.getAll(); - List l = new ArrayList(Arrays.asList(defs)); + List l = new ArrayList(Arrays.asList(defs)); assertTrue(l.remove(privilegeRegistry.get(NameConstants.JCR_READ))); assertTrue(l.remove(privilegeRegistry.get(NameConstants.JCR_ADD_CHILD_NODES))); assertTrue(l.remove(privilegeRegistry.get(NameConstants.JCR_REMOVE_CHILD_NODES))); @@ -85,9 +84,9 @@ public class PrivilegeRegistryTest exten public void testGet() throws RepositoryException { - for (PrivilegeRegistry.PrivilegeDefinition def : privilegeRegistry.getAll()) { + for (PrivilegeRegistry.Definition def : privilegeRegistry.getAll()) { - PrivilegeRegistry.PrivilegeDefinition d = privilegeRegistry.get(def.name); + PrivilegeRegistry.Definition d = privilegeRegistry.get(def.name); assertEquals(def, d); assertNotNull(d.name); @@ -107,14 +106,14 @@ public class PrivilegeRegistryTest exten public void testAggregates() throws RepositoryException { - for (PrivilegeRegistry.PrivilegeDefinition def : privilegeRegistry.getAll()) { + for (PrivilegeRegistry.Definition def : privilegeRegistry.getAll()) { if (def.declaredAggregateNames.isEmpty()) { continue; // ignore non aggregate } List l = Arrays.asList(def.getDeclaredAggregateNames()); for (Name n : l) { - PrivilegeRegistry.PrivilegeDefinition d = privilegeRegistry.get(n); + PrivilegeRegistry.Definition d = privilegeRegistry.get(n); assertNotNull(d); Name[] names = privilegeRegistry.getNames(d.getBits()); assertNotNull(names); @@ -126,7 +125,7 @@ public class PrivilegeRegistryTest exten public void testPrivilegeDefinition() throws RepositoryException { - for (PrivilegeRegistry.PrivilegeDefinition def : privilegeRegistry.getAll()) { + for (PrivilegeRegistry.Definition def : privilegeRegistry.getAll()) { assertNotNull(def.name); assertEquals(def.name, def.getName()); @@ -144,7 +143,7 @@ public class PrivilegeRegistryTest exten } public void testJcrAll() throws RepositoryException { - PrivilegeRegistry.PrivilegeDefinition p = privilegeRegistry.get(NameConstants.JCR_ALL); + PrivilegeRegistry.Definition p = privilegeRegistry.get(NameConstants.JCR_ALL); assertEquals(p.getName(), NameConstants.JCR_ALL); assertFalse(p.declaredAggregateNames.isEmpty()); assertFalse(p.isAbstract()); @@ -165,7 +164,7 @@ public class PrivilegeRegistryTest exten public void testJcrWrite() throws RepositoryException { Name rw = resolver.getQName(PrivilegeRegistry.REP_WRITE); - PrivilegeRegistry.PrivilegeDefinition p = privilegeRegistry.get(rw); + PrivilegeRegistry.Definition p = privilegeRegistry.get(rw); assertEquals(p.getName(), rw); assertFalse(p.declaredAggregateNames.isEmpty()); @@ -178,7 +177,7 @@ public class PrivilegeRegistryTest exten } public void testRepWrite() throws RepositoryException { - PrivilegeRegistry.PrivilegeDefinition p = privilegeRegistry.get(NameConstants.JCR_WRITE); + PrivilegeRegistry.Definition p = privilegeRegistry.get(NameConstants.JCR_WRITE); assertEquals(p.getName(), NameConstants.JCR_WRITE); assertFalse(p.declaredAggregateNames.isEmpty()); assertFalse(p.isAbstract()); @@ -436,7 +435,7 @@ public class PrivilegeRegistryTest exten resource.makeParentDirs(); } StringBuilder sb = new StringBuilder(); - sb.append("test;;test2\n"); + sb.append(""); Writer writer = new OutputStreamWriter(resource.getOutputStream(), "utf-8"); writer.write(sb.toString()); @@ -446,7 +445,7 @@ public class PrivilegeRegistryTest exten try { new PrivilegeRegistry(superuser.getWorkspace().getNamespaceRegistry(), fs); fail("Invalid names must be detected upon registry startup."); - } catch (IllegalArgumentException e) { + } catch (RepositoryException e) { // success } finally { fs.deleteFolder("/privileges"); @@ -537,12 +536,13 @@ public class PrivilegeRegistryTest exten Map> newCustomPrivs = new HashMap>(); newCustomPrivs.put(resolver.getQName("new"), Collections.emptySet()); + newCustomPrivs.put(resolver.getQName("test:new"), Collections.emptySet()); for (Name name : newCustomPrivs.keySet()) { boolean isAbstract = true; Set aggrNames = newCustomPrivs.get(name); pr.registerDefinition(name, isAbstract, aggrNames); - PrivilegeRegistry.PrivilegeDefinition definition = pr.get(name); + PrivilegeRegistry.Definition definition = pr.get(name); assertNotNull(definition); assertEquals(name, definition.getName()); @@ -558,7 +558,7 @@ public class PrivilegeRegistryTest exten // re-read the filesystem resource and check if definition is correct PrivilegeRegistry registry = new PrivilegeRegistry(superuser.getWorkspace().getNamespaceRegistry(), fs); - PrivilegeRegistry.PrivilegeDefinition def = registry.get(name); + PrivilegeRegistry.Definition def = registry.get(name); assertEquals(isAbstract, def.isAbstract); assertEquals(aggrNames.size(), def.declaredAggregateNames.size()); for (Name n : aggrNames) { @@ -571,12 +571,13 @@ public class PrivilegeRegistryTest exten newAggregates.put(resolver.getQName("newA1"), createNameSet(NameConstants.JCR_READ, NameConstants.JCR_RETENTION_MANAGEMENT)); // a new aggregate of custom and built-in privilege newAggregates.put(resolver.getQName("newA2"), createNameSet(resolver.getQName("new"), NameConstants.JCR_READ)); + newAggregates.put(resolver.getQName("newA3"), createNameSet(resolver.getQName("test:new"), resolver.getQName("new"))); for (Name name : newAggregates.keySet()) { boolean isAbstract = false; Set aggrNames = newAggregates.get(name); pr.registerDefinition(name, isAbstract, aggrNames); - PrivilegeRegistry.PrivilegeDefinition definition = pr.get(name); + PrivilegeRegistry.Definition definition = pr.get(name); assertNotNull(definition); assertEquals(name, definition.getName()); @@ -592,7 +593,7 @@ public class PrivilegeRegistryTest exten // re-read the filesystem resource and check if definition is correct PrivilegeRegistry registry = new PrivilegeRegistry(superuser.getWorkspace().getNamespaceRegistry(), fs); - PrivilegeRegistry.PrivilegeDefinition def = registry.get(name); + PrivilegeRegistry.Definition def = registry.get(name); assertEquals(isAbstract, def.isAbstract); assertEquals(isAbstract, def.isAbstract); assertEquals(aggrNames.size(), def.declaredAggregateNames.size()); Added: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/ParseException.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/ParseException.java?rev=1081433&view=auto ============================================================================== --- jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/ParseException.java (added) +++ jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/ParseException.java Mon Mar 14 16:00:40 2011 @@ -0,0 +1,31 @@ +/* + * 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.commons.privilege; + +/** + * ParseException... + */ +public class ParseException extends Exception { + + public ParseException(Throwable throwable) { + super(throwable); + } + + public ParseException(String s, Throwable throwable) { + super(s, throwable); + } +} \ No newline at end of file Propchange: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/ParseException.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/ParseException.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Rev URL Added: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeDefinition.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeDefinition.java?rev=1081433&view=auto ============================================================================== --- jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeDefinition.java (added) +++ jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeDefinition.java Mon Mar 14 16:00:40 2011 @@ -0,0 +1,44 @@ +/* + * 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.commons.privilege; + +/** + * PrivilegeDefinition + */ +public class PrivilegeDefinition { + private final String name; + private final boolean isAbstract; + private final String[] declaredAggregateNames; + + public PrivilegeDefinition(String name, boolean isAbstract, String[] declaredAggregateNames) { + this.name = name; + this.isAbstract = isAbstract; + this.declaredAggregateNames = declaredAggregateNames; + } + + public String getName() { + return name; + } + + public boolean isAbstract() { + return isAbstract; + } + + public String[] getDeclaredAggregateNames() { + return declaredAggregateNames; + } +} \ No newline at end of file Propchange: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeDefinition.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeDefinition.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Rev URL Added: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeDefinitionReader.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeDefinitionReader.java?rev=1081433&view=auto ============================================================================== --- jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeDefinitionReader.java (added) +++ jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeDefinitionReader.java Mon Mar 14 16:00:40 2011 @@ -0,0 +1,72 @@ +/* + * 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.commons.privilege; + +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +/** + * Reads privilege definitions for the specified InputStream. Note, + * that this reader will not apply any validation. + */ +public class PrivilegeDefinitionReader { + + private final PrivilegeDefinition[] privilegeDefinitions; + private final Map namespaces = new HashMap(); + + /** + * Creates a new PrivilegeDefinitionReader for the given + * input stream. The specified content type is used in order to determine + * the type of privilege serialization. + * + * @param in The input stream to read the privilege definitions from. + * @param contentType Currently only types supported by + * {@link PrivilegeXmlHandler#isSupportedContentType(String)PrivilegeXmlHandler} + * are allowed. + * @throws ParseException If an error occurs. + * @throws IllegalArgumentException if the specified content type is not supported. + */ + public PrivilegeDefinitionReader(InputStream in, String contentType) throws ParseException { + if (PrivilegeXmlHandler.isSupportedContentType(contentType)) { + PrivilegeHandler pxh = new PrivilegeXmlHandler(); + privilegeDefinitions = pxh.readDefinitions(in, namespaces); + } else { + // not yet supported + throw new IllegalArgumentException("Unsupported content type " + contentType); + } + } + + /** + * Returns the privilege definitions retrieved from the input stream. + * + * @return an array of PrivilegeDefinition + */ + public PrivilegeDefinition[] getPrivilegeDefinitions() { + return privilegeDefinitions; + } + + /** + * Returns the namespace mappings such as retrieved during parsing. + * + * @return a mapping of namespace prefix to uri used by the privilege + * definitions. + */ + public Map getNamespaces() { + return namespaces; + } +} \ No newline at end of file Propchange: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeDefinitionReader.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeDefinitionReader.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Rev URL Added: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeDefinitionWriter.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeDefinitionWriter.java?rev=1081433&view=auto ============================================================================== --- jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeDefinitionWriter.java (added) +++ jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeDefinitionWriter.java Mon Mar 14 16:00:40 2011 @@ -0,0 +1,60 @@ +/* + * 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.commons.privilege; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Map; + +/** + * Writes privilege definitions to an output stream. + */ +public class PrivilegeDefinitionWriter { + + private final PrivilegeHandler ph; + + /** + * Creates a new PrivilegeDefinitionWriter. + * + * @param contentType The content type used to determine the type of + * serialization. + * @throws IllegalArgumentException if the specified content type is not + * supported. + */ + public PrivilegeDefinitionWriter(String contentType) { + if (PrivilegeXmlHandler.isSupportedContentType(contentType)) { + ph = new PrivilegeXmlHandler(); + } else { + // not yet supported + throw new IllegalArgumentException("Unsupported content type"); + } + } + + /** + * Writes the privilege definitions to the specified output stream. + * + * @param out The output stream. + * @param privilegeDefinitions The privilege definitions to write to the + * given output stream. + * @param namespaces The namespace mapping (prefix to uri) used by the + * specified definitions. + * @throws IOException If an error occurs. + */ + public void writeDefinitions(OutputStream out, PrivilegeDefinition[] privilegeDefinitions, Map namespaces) throws IOException { + ph.writeDefinitions(out, privilegeDefinitions, namespaces); + } +} \ No newline at end of file Propchange: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeDefinitionWriter.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeDefinitionWriter.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Rev URL Added: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeHandler.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeHandler.java?rev=1081433&view=auto ============================================================================== --- jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeHandler.java (added) +++ jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeHandler.java Mon Mar 14 16:00:40 2011 @@ -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.commons.privilege; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Map; + +/** + * Interface used to define the (de)serialization mode of the privilege definitions. + */ +public interface PrivilegeHandler { + + /** + * Read the privilege definitions and update the specified namespace mapping. + * + * @param in + * @param namespaces + * @return the privilege definitions contained in the specified stream. + * @throws ParseException + */ + PrivilegeDefinition[] readDefinitions(InputStream in, Map namespaces) throws ParseException; + + /** + * Write the specified privilege definitions to the given output stream. + * + * @param out + * @param definitions + * @param namespaces + * @throws IOException + */ + void writeDefinitions(OutputStream out, PrivilegeDefinition[] definitions, Map namespaces) throws IOException; +} \ No newline at end of file Propchange: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeHandler.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeHandler.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Rev URL Added: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeXmlHandler.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeXmlHandler.java?rev=1081433&view=auto ============================================================================== --- jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeXmlHandler.java (added) +++ jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeXmlHandler.java Mon Mar 14 16:00:40 2011 @@ -0,0 +1,240 @@ +/* + * 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.commons.privilege; + +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * PrivilegeXmlHandler + */ +class PrivilegeXmlHandler implements PrivilegeHandler { + + private static final String TEXT_XML = "text/xml"; + private static final String APPLICATION_XML = "application/xml"; + + private static final String XML_PRIVILEGES = "privileges"; + private static final String XML_PRIVILEGE = "privilege"; + private static final String XML_CONTAINS = "contains"; + + private static final String ATTR_NAME = "name"; + private static final String ATTR_ABSTRACT = "abstract"; + + private static final String ATTR_XMLNS = "xmlns:"; + + /** + * Constant for DocumentBuilderFactory. + */ + private static DocumentBuilderFactory DOCUMENT_BUILDER_FACTORY = createFactory(); + + private static DocumentBuilderFactory createFactory() { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + factory.setIgnoringComments(true); + factory.setIgnoringElementContentWhitespace(true); + return factory; + } + + /** + * Constant for TransformerFactory + */ + private static TransformerFactory TRANSFORMER_FACTORY = TransformerFactory.newInstance(); + + /** + * Create a new instance. + */ + PrivilegeXmlHandler() { + + } + + /** + * Returns true if the specified content type can be handled by this class. + * + * @param contentType + * @return true if the specified content type can be handled + * by this class; false otherwise. + */ + static boolean isSupportedContentType(String contentType) { + return TEXT_XML.equals(contentType) || APPLICATION_XML.equals(contentType); + } + + //---------------------------------------------------< PrivilegeHandler >--- + /** + * @see PrivilegeHandler#readDefinitions(java.io.InputStream, java.util.Map) + */ + public PrivilegeDefinition[] readDefinitions(InputStream in, Map namespaces) throws ParseException { + try { + List defs = new ArrayList(); + + DocumentBuilder builder = createDocumentBuilder(); + Document doc = builder.parse(in); + Element root = doc.getDocumentElement(); + if (!XML_PRIVILEGES.equals(root.getNodeName())) { + throw new IllegalArgumentException("root element must be named 'privileges'"); + } + + updateNamespaceMapping(root, namespaces); + + NodeList nl = root.getElementsByTagName(XML_PRIVILEGE); + for (int i = 0; i < nl.getLength(); i++) { + Node n = nl.item(i); + PrivilegeDefinition def = parseDefinition(n, namespaces); + if (def != null) { + defs.add(def); + } + } + return defs.toArray(new PrivilegeDefinition[defs.size()]); + + } catch (SAXException e) { + throw new ParseException(e); + } catch (IOException e) { + throw new ParseException(e); + } catch (ParserConfigurationException e) { + throw new ParseException(e); + } + + } + + /** + * @see PrivilegeHandler#writeDefinitions(java.io.OutputStream, PrivilegeDefinition[], java.util.Map) + */ + public void writeDefinitions(OutputStream out, PrivilegeDefinition[] definitions, Map namespaces) throws IOException { + try { + DocumentBuilder builder = createDocumentBuilder(); + Document doc = builder.newDocument(); + Element privileges = (Element) doc.appendChild(doc.createElement(XML_PRIVILEGES)); + + for (String prefix : namespaces.keySet()) { + privileges.setAttribute(ATTR_XMLNS + prefix, namespaces.get(prefix)); + } + + for (PrivilegeDefinition def : definitions) { + Element priv = (Element) privileges.appendChild(doc.createElement(XML_PRIVILEGE)); + priv.setAttribute(ATTR_NAME, def.getName()); + priv.setAttribute(ATTR_ABSTRACT, Boolean.valueOf(def.isAbstract()).toString()); + + for (String aggrName : def.getDeclaredAggregateNames()) { + Element contains = (Element) priv.appendChild(doc.createElement(XML_CONTAINS)); + contains.setAttribute(ATTR_NAME, aggrName); + } + } + + Transformer transformer = TRANSFORMER_FACTORY.newTransformer(); + transformer.transform(new DOMSource(doc), new StreamResult(out)); + + } catch (Exception e) { + IOException io = new IOException(e.getMessage()); + io.initCause(e); + throw io; + } + } + + //-------------------------------------------------------------------------- + /** + * Build a new PrivilegeDefinition from the given XML node. + * @param n + * @param namespaces + * @return + */ + private PrivilegeDefinition parseDefinition(Node n, Map namespaces) { + if (n.getNodeType() == Node.ELEMENT_NODE) { + Element elem = (Element) n; + + updateNamespaceMapping(elem, namespaces); + + String name = elem.getAttribute(ATTR_NAME); + boolean isAbstract = Boolean.parseBoolean(elem.getAttribute(ATTR_ABSTRACT)); + + List aggrNames = new ArrayList(); + NodeList nodeList = elem.getChildNodes(); + for (int i = 0; i < nodeList.getLength(); i++) { + Node contains = nodeList.item(i); + if (isElement(n) && XML_CONTAINS.equals(contains.getNodeName())) { + String aggrName = ((Element) contains).getAttribute(ATTR_NAME); + if (aggrName != null) { + aggrNames.add(aggrName); + } + } + } + return new PrivilegeDefinition(name, isAbstract, aggrNames.toArray(new String[aggrNames.size()])); + } + + // could not parse into privilege definition + return null; + } + + /** + * Create a new DocumentBuilder + * + * @return a new DocumentBuilder + * @throws ParserConfigurationException + */ + private static DocumentBuilder createDocumentBuilder() throws ParserConfigurationException { + DocumentBuilder builder = DOCUMENT_BUILDER_FACTORY.newDocumentBuilder(); + builder.setErrorHandler(new DefaultHandler()); + return builder; + } + + /** + * Update the specified namespace mappings with the namespace declarations + * defined by the given XML element. + * + * @param elem + * @param namespaces + */ + private static void updateNamespaceMapping(Element elem, Map namespaces) { + NamedNodeMap attributes = elem.getAttributes(); + for (int i = 0; i < attributes.getLength(); i++) { + Attr attr = (Attr) attributes.item(i); + if (attr.getName().startsWith(ATTR_XMLNS)) { + String prefix = attr.getName().substring(ATTR_XMLNS.length()); + String uri = attr.getValue(); + namespaces.put(prefix, uri); + } + } + } + + /** + * Returns true if the given XML node is an element. + * + * @param n + * @return true if the given XML node is an element; false otherwise. + */ + private static boolean isElement(Node n) { + return n.getNodeType() == Node.ELEMENT_NODE; + } +} \ No newline at end of file Propchange: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeXmlHandler.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/privilege/PrivilegeXmlHandler.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Rev URL