You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by ju...@apache.org on 2014/01/14 17:32:05 UTC
svn commit: r1558101 - in /jackrabbit/oak/trunk:
oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/
oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/
oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/security/
Author: jukka
Date: Tue Jan 14 16:32:05 2014
New Revision: 1558101
URL: http://svn.apache.org/r1558101
Log:
OAK-519: Migration of custom jr2.x privileges into OAK
Add Angela's PrivilegeMigrator to oak-upgrade.
Not integrated into the main RepositoryUpgrade class yet.
Added:
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/security/PrivilegeMigrator.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeDefinitionWriter.java
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeDefinitionWriter.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeDefinitionWriter.java?rev=1558101&r1=1558100&r2=1558101&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeDefinitionWriter.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeDefinitionWriter.java Tue Jan 14 16:32:05 2014
@@ -42,7 +42,7 @@ import org.apache.jackrabbit.oak.util.No
* PrivilegeDefinitionWriter is responsible for writing privilege definitions
* to the repository without applying any validation checks.
*/
-class PrivilegeDefinitionWriter implements PrivilegeConstants {
+public class PrivilegeDefinitionWriter implements PrivilegeConstants {
/**
* The internal names of all built-in privileges that are not aggregates.
@@ -71,7 +71,7 @@ class PrivilegeDefinitionWriter implemen
private PrivilegeBits next;
- PrivilegeDefinitionWriter(Root root) {
+ public PrivilegeDefinitionWriter(Root root) {
this.root = root;
this.bitsMgr = new PrivilegeBitsProvider(root);
Tree privilegesTree = bitsMgr.getPrivilegesTree();
@@ -88,7 +88,7 @@ class PrivilegeDefinitionWriter implemen
* @param definition The new privilege definition.
* @throws RepositoryException If the definition can't be written.
*/
- void writeDefinition(PrivilegeDefinition definition) throws RepositoryException {
+ public void writeDefinition(PrivilegeDefinition definition) throws RepositoryException {
writeDefinitions(Collections.singleton(definition));
}
Modified: jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java?rev=1558101&r1=1558100&r2=1558101&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java (original)
+++ jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java Tue Jan 14 16:32:05 2014
@@ -276,6 +276,7 @@ public class RepositoryUpgrade {
Map<Integer, String> idxToPrefix = copyNamespaces(builder);
copyNodeTypes(builder);
+ copyPrivileges(builder);
copyVersionStore(builder, idxToPrefix);
copyWorkspaces(builder, idxToPrefix);
@@ -378,6 +379,10 @@ public class RepositoryUpgrade {
return properties;
}
+ private void copyPrivileges(NodeBuilder root) throws RepositoryException {
+ // TODO
+ }
+
private void copyNodeTypes(NodeBuilder root) throws RepositoryException {
NodeTypeRegistry sourceRegistry = source.getNodeTypeRegistry();
NodeBuilder system = root.child(JCR_SYSTEM);
Added: jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/security/PrivilegeMigrator.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/security/PrivilegeMigrator.java?rev=1558101&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/security/PrivilegeMigrator.java (added)
+++ jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/security/PrivilegeMigrator.java Tue Jan 14 16:32:05 2014
@@ -0,0 +1,264 @@
+/*
+ * 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.oak.upgrade.security;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.jcr.NamespaceRegistry;
+import javax.jcr.RepositoryException;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.jackrabbit.oak.api.ContentSession;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.plugins.name.ReadWriteNamespaceRegistry;
+import org.apache.jackrabbit.oak.security.privilege.PrivilegeDefinitionWriter;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeDefinition;
+import org.apache.jackrabbit.oak.spi.security.privilege.ImmutablePrivilegeDefinition;
+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.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * PrivilegeMigrator is a utility to migrate custom privilege definitions from
+ * a jackrabbit 2 project to oak.
+ * <p/>
+ * TODO: this is an initial draft of a migration tool from jr2 custom privileges
+ * TODO: to oak. might need to be adjusted once we have defined a upgrade path (see OAK-458)
+ */
+public class PrivilegeMigrator {
+
+ private final ContentSession contentSession;
+
+ public PrivilegeMigrator(ContentSession contentSession) {
+ this.contentSession = contentSession;
+ }
+
+ public void migrateCustomPrivileges(InputStream privilegeStream) throws RepositoryException {
+ final Root root = contentSession.getLatestRoot();
+ PrivilegeDefinitionWriter writer = new PrivilegeDefinitionWriter(root);
+ try {
+ NamespaceRegistry nsRegistry = new ReadWriteNamespaceRegistry() {
+ @Override
+ protected Root getWriteRoot() {
+ return root;
+ }
+
+ @Override
+ protected Tree getReadTree() {
+ return root.getTree("/");
+ }
+ };
+ for (PrivilegeDefinition def : readCustomDefinitions(privilegeStream, nsRegistry)) {
+ writer.writeDefinition(def);
+ }
+ } catch (IOException e) {
+ throw new RepositoryException(e);
+ }
+ }
+
+ /**
+ * Reads privilege definitions for the specified {@code InputStream}. The
+ * aim of this method is to provide backwards compatibility with
+ * custom privilege definitions of Jackrabbit 2.x repositories. The caller
+ * is in charge of migrating the definitions.
+ *
+ * @param customPrivileges The stream from which 2.x privilege definitions
+ * should be read.
+ * @param nsRegistry The namespace registry.
+ * @return The {@code PrivilegeDefinition}s contained in the stream.
+ * @throws RepositoryException If a name collisions is detected during
+ * parsing the custom privileges.
+ * @throws IOException If another error occurs while reading from the
+ * custom privileges stream.
+ */
+ private static Iterable<PrivilegeDefinition> readCustomDefinitions(InputStream customPrivileges,
+ NamespaceRegistry nsRegistry)
+ throws RepositoryException, IOException {
+ Map<String, PrivilegeDefinition> definitions = new LinkedHashMap<String, PrivilegeDefinition>();
+ InputSource src = new InputSource(customPrivileges);
+ for (PrivilegeDefinition def : PrivilegeXmlHandler.readDefinitions(src, nsRegistry)) {
+ String privName = def.getName();
+ if (definitions.containsKey(privName)) {
+ throw new RepositoryException("Duplicate entry for custom privilege with name " + privName);
+ }
+ definitions.put(privName, def);
+ }
+ return definitions.values();
+ }
+
+ //--------------------------------------------------------------------------
+
+ /**
+ * The {@code PrivilegeXmlHandler} loads privilege definitions from a XML
+ * document using the following format:
+ * <pre>
+ * <!DOCTYPE privileges [
+ * <!ELEMENT privileges (privilege)+>
+ * <!ELEMENT privilege (contains)+>
+ * <!ATTLIST privilege abstract (true|false) false>
+ * <!ATTLIST privilege name NMTOKEN #REQUIRED>
+ * <!ELEMENT contains EMPTY>
+ * <!ATTLIST contains name NMTOKEN #REQUIRED>
+ * ]>
+ * </pre>
+ */
+ private static class PrivilegeXmlHandler {
+
+ 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:";
+
+ private static DocumentBuilderFactory createFactory() {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ factory.setIgnoringComments(false);
+ factory.setIgnoringElementContentWhitespace(true);
+ return factory;
+ }
+
+ private static PrivilegeDefinition[] readDefinitions(InputSource input,
+ NamespaceRegistry nsRegistry) throws RepositoryException, IOException {
+ try {
+ List<PrivilegeDefinition> defs = new ArrayList<PrivilegeDefinition>();
+
+ DocumentBuilder builder = createDocumentBuilder();
+ Document doc = builder.parse(input);
+ Element root = doc.getDocumentElement();
+ if (!XML_PRIVILEGES.equals(root.getNodeName())) {
+ throw new IllegalArgumentException("root element must be named 'privileges'");
+ }
+
+ updateNamespaceMapping(root, nsRegistry);
+
+ NodeList nl = root.getElementsByTagName(XML_PRIVILEGE);
+ for (int i = 0; i < nl.getLength(); i++) {
+ Node n = nl.item(i);
+ PrivilegeDefinition def = parseDefinition(n, nsRegistry);
+ if (def != null) {
+ defs.add(def);
+ }
+ }
+ return defs.toArray(new PrivilegeDefinition[defs.size()]);
+
+ } catch (SAXException e) {
+ throw new RepositoryException(e);
+ } catch (ParserConfigurationException e) {
+ throw new RepositoryException(e);
+ }
+ }
+
+ /**
+ * Build a new {@code PrivilegeDefinition} from the given XML node.
+ *
+ * @param n the xml node storing the privilege definition.
+ * @param nsRegistry
+ * @return a new PrivilegeDefinition.
+ * @throws javax.jcr.RepositoryException
+ */
+ private static PrivilegeDefinition parseDefinition(Node n, NamespaceRegistry nsRegistry) throws RepositoryException {
+ if (n.getNodeType() == Node.ELEMENT_NODE) {
+ Element elem = (Element) n;
+
+ updateNamespaceMapping(elem, nsRegistry);
+
+ String name = elem.getAttribute(ATTR_NAME);
+ boolean isAbstract = Boolean.parseBoolean(elem.getAttribute(ATTR_ABSTRACT));
+
+ Set<String> aggrNames = new HashSet<String>();
+ 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 ImmutablePrivilegeDefinition(name, isAbstract, aggrNames);
+ }
+
+ // could not parse into privilege definition
+ return null;
+ }
+
+ /**
+ * Create a new {@code DocumentBuilder}
+ *
+ * @return a new {@code DocumentBuilder}
+ * @throws ParserConfigurationException If an error occurs.
+ */
+ private static DocumentBuilder createDocumentBuilder() throws ParserConfigurationException {
+ DocumentBuilder builder = createFactory().newDocumentBuilder();
+ builder.setErrorHandler(new DefaultHandler());
+ return builder;
+ }
+
+ /**
+ * Update the specified nsRegistry mappings with the nsRegistry declarations
+ * defined by the given XML element.
+ *
+ * @param elem An XML element.
+ * @param nsRegistry The namespace registry used to keep track of the
+ * namespace definitions present in the xml file.
+ * @throws javax.jcr.RepositoryException If error occurs.
+ */
+ private static void updateNamespaceMapping(Element elem, NamespaceRegistry nsRegistry) throws RepositoryException {
+ 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();
+ nsRegistry.registerNamespace(prefix, uri);
+ }
+ }
+ }
+
+ /**
+ * Returns {@code true} if the given XML node is an element.
+ *
+ * @param n
+ * @return {@code true} if the given XML node is an element; {@code false} otherwise.
+ */
+ private static boolean isElement(Node n) {
+ return n.getNodeType() == Node.ELEMENT_NODE;
+ }
+ }
+
+}