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 2013/08/10 07:53:54 UTC

svn commit: r1512568 [17/39] - in /jackrabbit/commons/filevault/trunk: ./ parent/ vault-cli/ vault-cli/src/ vault-cli/src/main/ vault-cli/src/main/appassembler/ vault-cli/src/main/assembly/ vault-cli/src/main/java/ vault-cli/src/main/java/org/ vault-cl...

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/JcrArchive.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/JcrArchive.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/JcrArchive.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/JcrArchive.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,389 @@
+/*
+ * 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.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.vault.fs.api.PathFilterSet;
+import org.apache.jackrabbit.vault.fs.api.VaultInputSource;
+import org.apache.jackrabbit.vault.fs.config.ConfigurationException;
+import org.apache.jackrabbit.vault.fs.config.DefaultMetaInf;
+import org.apache.jackrabbit.vault.fs.config.DefaultWorkspaceFilter;
+import org.apache.jackrabbit.vault.fs.config.MetaInf;
+import org.apache.jackrabbit.vault.fs.config.VaultSettings;
+import org.apache.jackrabbit.vault.fs.spi.CNDReader;
+import org.apache.jackrabbit.vault.fs.spi.ServiceProviderFactory;
+import org.apache.jackrabbit.vault.util.Constants;
+import org.apache.jackrabbit.vault.util.JcrConstants;
+import org.apache.jackrabbit.vault.util.Text;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implements an archive that is based on nt:file/nt:folder nodes in a JCR
+ * repository.
+ */
+public class JcrArchive extends AbstractArchive {
+
+    /**
+     * default logger
+     */
+    private static final Logger log = LoggerFactory.getLogger(JcrArchive.class);
+
+    private Node archiveRoot;
+
+    private final String rootPath;
+
+    private DefaultMetaInf inf;
+
+    private Entry jcrRoot;
+
+    private String chRoot;
+
+    public JcrArchive(Node archiveRoot, String rootPath) {
+        this.archiveRoot = archiveRoot;
+        this.rootPath = rootPath;
+    }
+
+    public void open(boolean strict) throws IOException {
+        try {
+            if (archiveRoot.hasNode(Constants.ROOT_DIR)) {
+                jcrRoot = new JcrEntry(archiveRoot.getNode(Constants.ROOT_DIR), Constants.ROOT_DIR, true);
+            } else {
+                jcrRoot = new JcrEntry(archiveRoot, archiveRoot.getName(), true);
+            }
+            if (archiveRoot.hasNode(Constants.META_DIR)) {
+                inf = loadMetaInf(
+                        new JcrEntry(archiveRoot.getNode(Constants.META_DIR), Constants.META_DIR, true),
+                        strict);
+            } else {
+                inf = new DefaultMetaInf();
+                inf.setSettings(VaultSettings.createDefault());
+                DefaultWorkspaceFilter filter = new DefaultWorkspaceFilter();
+                PathFilterSet filterSet = new PathFilterSet(rootPath);
+                filter.add(filterSet);
+                inf.setFilter(filter);
+
+                // if archive is rooted, create intermediate entries
+                if (chRoot != null && chRoot.length() > 0) {
+                    String[] roots = Text.explode(rootPath, '/');
+                    if (roots.length > 0) {
+                        VirtualEntry newRoot = new VirtualEntry(jcrRoot.getName());
+                        VirtualEntry entry = newRoot;
+                        for (String name: roots) {
+                            VirtualEntry newEntry = new VirtualEntry(name);
+                            entry.children.put(name, newEntry);
+                            entry = newEntry;
+                        }
+                        for (Entry e: jcrRoot.getChildren()) {
+                            entry.children.put(e.getName(), e);
+                        }
+                        jcrRoot = newRoot;
+                    }
+                }
+            }
+        } catch (RepositoryException e) {
+            IOException ie = new IOException("Error while opening JCR archive.");
+            ie.initCause(e);
+            throw ie;
+        } catch (ConfigurationException e) {
+            IOException ie = new IOException("Error while opening JCR archive.");
+            ie.initCause(e);
+            throw ie;
+        }
+    }
+
+    private DefaultMetaInf loadMetaInf(Entry dir, boolean strict)
+            throws IOException, ConfigurationException {
+        DefaultMetaInf inf = new DefaultMetaInf();
+        // filter
+        for (Entry entry: dir.getChildren()) {
+            String name = entry.getName();
+            VaultInputSource src = getInputSource(entry);
+            if (name.equals(Constants.FILTER_XML)) {
+                // load filter
+                inf.loadFilter(src.getByteStream(), src.getSystemId());
+            } else if (name.equals(Constants.CONFIG_XML)) {
+                // load config
+                inf.loadConfig(src.getByteStream(), src.getSystemId());
+            } else if (name.equals(Constants.SETTINGS_XML)) {
+                // load settings
+                inf.loadSettings(src.getByteStream(), src.getSystemId());
+            } else if (name.equals(Constants.PROPERTIES_XML)) {
+                // load properties
+                inf.loadProperties(src.getByteStream(), src.getSystemId());
+            } else if (name.equals(Constants.PRIVILEGES_XML)) {
+                // load privileges
+                inf.loadPrivileges(src.getByteStream(), src.getSystemId());
+            } else if (name.equals(Constants.PACKAGE_DEFINITION_XML)) {
+                inf.setHasDefinition(true);
+                log.info("Contains package definition {}.", src.getSystemId());
+            } else if (name.endsWith(".cnd")) {
+                try {
+                    Reader r = new InputStreamReader(src.getByteStream(), "utf8");
+                    CNDReader reader = ServiceProviderFactory.getProvider().getCNDReader();
+                    reader.read(r, entry.getName(), null);
+                    inf.getNodeTypes().add(reader);
+                    log.info("Loaded nodetypes from {}.", src.getSystemId());
+                } catch (IOException e1) {
+                    log.error("Error while reading CND: {}", e1.toString());
+                    if (strict) {
+                        throw e1;
+                    }
+                }
+            }
+        }
+        if (inf.getFilter() == null) {
+            log.info("Archive {} does not contain filter definition.", this);
+        }
+        if (inf.getConfig() == null) {
+            log.info("Archive {} does not contain vault config.", this);
+        }
+        if (inf.getSettings() == null) {
+            log.info("Archive {} does not contain vault settings. using default.", this);
+            VaultSettings settings = new VaultSettings();
+            settings.getIgnoredNames().add(".svn");
+            inf.setSettings(settings);
+        }
+        if (inf.getProperties() == null) {
+            log.info("Archive {} does not contain properties.", this);
+        }
+        if (inf.getNodeTypes().isEmpty()) {
+            log.info("Archive {} does not contain nodetypes.", this);
+        }
+        return inf;
+    }
+
+    public void close() {
+        archiveRoot = null;
+        jcrRoot = null;
+    }
+
+    public Entry getJcrRoot() {
+        return jcrRoot;
+    }
+
+    public Entry getRoot() throws IOException {
+        return new JcrEntry(archiveRoot, "", true);
+    }
+
+    public MetaInf getMetaInf() {
+        return inf;
+    }
+
+    public InputStream openInputStream(Entry entry) throws IOException {
+        if (entry == null || entry.isDirectory()) {
+            return null;
+        }
+        try {
+            Node content = ((JcrEntry) entry).node.getNode(JcrConstants.JCR_CONTENT);
+            return content.getProperty(JcrConstants.JCR_DATA).getBinary().getStream();
+        } catch (RepositoryException e) {
+            IOException e1 = new IOException("Unable to open input source.");
+            e1.initCause(e);
+            throw e1;
+        }
+    }
+
+    public VaultInputSource getInputSource(final Entry entry) throws IOException {
+        if (entry == null || entry.isDirectory()) {
+            return null;
+        }
+        try {
+            final Node content = ((JcrEntry) entry).node.getNode(JcrConstants.JCR_CONTENT);
+            final String systemId = ((JcrEntry) entry).node.getPath();
+            return new VaultInputSource() {
+
+                {
+                    setSystemId(systemId);
+                }
+
+                public InputStream getByteStream() {
+                    try {
+                        // todo: handle releasing of binary ?
+                        return content.getProperty(JcrConstants.JCR_DATA).getBinary().getStream();
+                    } catch (RepositoryException e) {
+                        log.error("Error while opening input stream of " + content, e);
+                        return null;
+                    }
+                }
+
+                /**
+                 * {@inheritDoc}
+                 */
+                public long getContentLength() {
+                    try {
+                        return content.getProperty(JcrConstants.JCR_DATA).getLength();
+                    } catch (RepositoryException e) {
+                        log.error("Error while retrieving length of " + content, e);
+                        return -1;
+                    }
+                }
+
+                /**
+                 * {@inheritDoc}
+                 */
+                public long getLastModified() {
+                    try {
+                        return content.getProperty(JcrConstants.JCR_LASTMODIFIED).getDate().getTimeInMillis();
+                    } catch (RepositoryException e) {
+                        log.error("Error while retrieving last modified of " + content, e);
+                        return 0;
+                    }
+                }
+
+            };
+
+        } catch (RepositoryException e) {
+            IOException e1 = new IOException("Unable to open input source.");
+            e1.initCause(e);
+            throw e1;
+        }
+    }
+
+    @Override
+    public String toString() {
+        try {
+            return archiveRoot.getPath();
+        } catch (RepositoryException e) {
+            return archiveRoot.toString();
+        }
+    }
+
+    private static class VirtualEntry implements Entry {
+
+        private final String name;
+
+        private Map<String, Entry> children = new LinkedHashMap<String, Entry>();
+
+        private VirtualEntry(String name) {
+            this.name = name;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public boolean isDirectory() {
+            return true;
+        }
+
+        public Collection<? extends Entry> getChildren() {
+            return children.values();
+        }
+
+        public Entry getChild(String name) {
+            return children.get(name);
+        }
+    }
+
+    private static class JcrEntry implements Entry {
+
+        private final Node node;
+
+        private final boolean isDir;
+
+        private final String name;
+
+        private JcrEntry(Node node, String name, boolean isDir) {
+            this.node = node;
+            this.isDir = isDir;
+            this.name = name;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public boolean isDirectory() {
+            return isDir;
+        }
+
+        public Collection<Entry> getChildren() {
+            if (isDir) {
+                try {
+                    NodeIterator iter = node.getNodes();
+                    long size = iter.getSize();
+                    if (size < 0) {
+                        size = 0;
+                    }
+                    List<Entry> ret = new ArrayList<Entry>((int) size);
+                    while (iter.hasNext()) {
+                        Node child = iter.nextNode();
+                        String name = child.getName();
+                        if (name.equals(".svn")) {
+                            // skip already
+                            continue;
+                        }
+                        boolean isDir;
+                        if (child.isNodeType("nt:folder")) {
+                            isDir = true;
+                        } else if (child.isNodeType("nt:file")) {
+                            isDir = false;
+                        } else {
+                            log.info("Skipping node {} with unknown type {}.", child.getPath(), child.getPrimaryNodeType().getName());
+                            continue;
+                        }
+                        ret.add(new JcrEntry(child, name, isDir));
+                    }
+                    return ret;
+                } catch (RepositoryException e) {
+                    log.error("Error while listing child nodes of {}", node, e);
+                    throw new IllegalStateException("Error while listing child nodes of " + node, e);
+                }
+            }
+            return Collections.emptyList();
+        }
+
+        public Entry getChild(String name) {
+            try {
+                if (isDir && node.hasNode(name) && !name.equals(".svn")) {
+                    Node child = node.getNode(name);
+                    boolean isDir;
+                    if (child.isNodeType("nt:folder")) {
+                        isDir = true;
+                    } else if (child.isNodeType("nt:file")) {
+                        isDir = false;
+                    } else {
+                        log.info("Skipping node {} with unknown type {}.", child.getPath(), child.getPrimaryNodeType().getName());
+                        return null;
+                    }
+                    return new JcrEntry(child, name, isDir);
+                }
+                return null;
+            } catch (RepositoryException e) {
+                log.error("Error while retrieving child node of {}", node, e);
+                throw new IllegalStateException("Error while retrieving child node of " + node, e);
+            }
+        }
+    }
+
+}
\ No newline at end of file

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/JcrExporter.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/JcrExporter.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/JcrExporter.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/JcrExporter.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,210 @@
+/*
+ * 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.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Calendar;
+
+import javax.jcr.Binary;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.vault.fs.api.Artifact;
+import org.apache.jackrabbit.vault.fs.api.VaultFile;
+import org.apache.jackrabbit.vault.util.JcrConstants;
+import org.apache.jackrabbit.vault.util.PathUtil;
+import org.apache.jackrabbit.vault.util.PlatformNameFormat;
+import org.apache.jackrabbit.vault.util.Text;
+
+/**
+ * Implements a Vault filesystem exporter that exports Vault files to a JCR
+ * repository.
+ * It uses the {@link PlatformNameFormat} for formatting the jcr file
+ * names to local ones.
+ */
+public class JcrExporter extends AbstractExporter {
+
+    private final Node localParent;
+
+    private boolean autoDeleteFiles;
+
+    /**
+     * Constructs a new jcr exporter.
+     * @param localFile the local parent folder
+     */
+    public JcrExporter(Node localFile) {
+        this.localParent = localFile;
+    }
+
+    public boolean isAutoDeleteFiles() {
+        return autoDeleteFiles;
+    }
+
+    public void setAutoDeleteFiles(boolean autoDeleteFiles) {
+        this.autoDeleteFiles = autoDeleteFiles;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void open() throws IOException, RepositoryException {
+        scan(localParent);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void close() throws IOException, RepositoryException {
+        if (autoDeleteFiles) {
+            for (ExportInfo.Entry e: exportInfo.getEntries().values()) {
+                if (e.type == ExportInfo.Type.DELETE) {
+                    String relPath = PathUtil.getRelativePath(localParent.getPath(), e.path);
+                    try {
+                        Node node = localParent.getNode(relPath);
+                        node.remove();
+                        track("D", relPath);
+                    } catch (RepositoryException e1) {
+                        track(e1, relPath);
+                    }
+                }
+            }
+        }
+        localParent.save();
+    }
+
+    private void scan(Node dir) throws RepositoryException {
+        NodeIterator iter = dir.getNodes();
+        while (iter.hasNext()) {
+            Node child = iter.nextNode();
+            String name = child.getName();
+            if (name.equals(".svn") || name.equals(".vlt")) {
+                continue;
+            }
+            if (child.isNodeType(JcrConstants.NT_FOLDER)) {
+                exportInfo.update(ExportInfo.Type.RMDIR, child.getPath());
+                scan(child);
+            } else if (child.isNodeType(JcrConstants.NT_FILE)) {
+                exportInfo.update(ExportInfo.Type.DELETE, child.getPath());
+            }
+        }
+    }
+
+    public void createDirectory(VaultFile file, String relPath)
+            throws RepositoryException, IOException {
+        getOrCreateItem(getPlatformFilePath(file, relPath), true);
+    }
+
+    public void createDirectory(String relPath) throws IOException {
+        getOrCreateItem(relPath, true);
+    }
+
+    public void writeFile(VaultFile file, String relPath)
+            throws RepositoryException, IOException {
+        Node local = getOrCreateItem(getPlatformFilePath(file, relPath), false);
+        track(local.isNew() ? "A" : "U", relPath);
+        Node content;
+        if (local.hasNode(JcrConstants.JCR_CONTENT)) {
+            content = local.getNode(JcrConstants.JCR_CONTENT);
+        } else {
+            content = local.addNode(JcrConstants.JCR_CONTENT, JcrConstants.NT_RESOURCE);
+        }
+        Artifact a = file.getArtifact();
+        switch (a.getPreferredAccess()) {
+            case NONE:
+                throw new RepositoryException("Artifact has no content.");
+
+            case SPOOL:
+                // we can't support spool
+            case STREAM:
+                InputStream in = a.getInputStream();
+                Binary b = content.getSession().getValueFactory().createBinary(in);
+                content.setProperty(JcrConstants.JCR_DATA, b);
+                b.dispose();
+                in.close();
+                break;
+        }
+        Calendar now = Calendar.getInstance();
+        if (a.getLastModified() >= 0) {
+            now.setTimeInMillis(a.getLastModified());
+        }
+        content.setProperty(JcrConstants.JCR_LASTMODIFIED, now);
+        if (a.getContentType() != null) {
+            content.setProperty(JcrConstants.JCR_MIMETYPE, a.getContentType());
+        } else if (!content.hasProperty(JcrConstants.JCR_MIMETYPE)){
+            content.setProperty(JcrConstants.JCR_MIMETYPE, "application/octet-stream");
+        }
+    }
+
+    public void writeFile(InputStream in, String relPath) throws IOException {
+        try {
+            Node content;
+            Node local = getOrCreateItem(relPath, false);
+            if (local.hasNode(JcrConstants.JCR_CONTENT)) {
+                content = local.getNode(JcrConstants.JCR_CONTENT);
+            } else {
+                content = local.addNode(JcrConstants.JCR_CONTENT, JcrConstants.NT_RESOURCE);
+            }
+            Binary b = content.getSession().getValueFactory().createBinary(in);
+            content.setProperty(JcrConstants.JCR_DATA, b);
+            content.setProperty(JcrConstants.JCR_LASTMODIFIED, Calendar.getInstance());
+            if (!content.hasProperty(JcrConstants.JCR_MIMETYPE)){
+                content.setProperty(JcrConstants.JCR_MIMETYPE, "application/octet-stream");
+            }
+            b.dispose();
+            in.close();
+        } catch (RepositoryException e) {
+            IOException io = new IOException("Error while writing file " + relPath);
+            io.initCause(e);
+            throw io;
+        }
+    }
+
+    private Node getOrCreateItem(String relPath, boolean isDir) throws IOException {
+        try {
+            String[] segments = Text.explode(relPath, '/');
+            Node root = localParent;
+            for (int i=0; i<segments.length; i++) {
+                String s = segments[i];
+                if (root.hasNode(s)) {
+                    root = root.getNode(s);
+                    if (isDir) {
+                        exportInfo.update(ExportInfo.Type.NOP, root.getPath());
+                    } else {
+                        exportInfo.update(ExportInfo.Type.UPDATE, root.getPath());
+                    }
+                } else {
+                    if (i == segments.length -1 && !isDir) {
+                        root = root.addNode(s, JcrConstants.NT_FILE);
+                        exportInfo.update(ExportInfo.Type.ADD, root.getPath());
+                    } else {
+                        root = root.addNode(s, JcrConstants.NT_FOLDER);
+                        exportInfo.update(ExportInfo.Type.MKDIR, root.getPath());
+                    }
+                }
+            }
+            return root;
+        } catch (RepositoryException e) {
+            IOException io = new IOException("Error while creating item " + relPath);
+            io.initCause(e);
+            throw io;
+        }
+    }
+
+}
\ No newline at end of file

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/PlatformExporter.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/PlatformExporter.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/PlatformExporter.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/PlatformExporter.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,183 @@
+/*
+ * 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.io;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.jackrabbit.vault.fs.api.Artifact;
+import org.apache.jackrabbit.vault.fs.api.VaultFile;
+import org.apache.jackrabbit.vault.util.Constants;
+import org.apache.jackrabbit.vault.util.PathUtil;
+import org.apache.jackrabbit.vault.util.PlatformNameFormat;
+
+/**
+ * Implements a Vault filesystem exporter that exports Vault files to a platform
+ * file system.
+ * It uses the {@link PlatformNameFormat} for formatting the jcr file
+ * names to local ones.
+ *
+ */
+public class PlatformExporter extends AbstractExporter {
+
+    private final File localParent;
+
+    private boolean pruneMissing;
+
+    /**
+     * Constructs a new jar exporter that writes to the given file.
+     * @param localFile the local parent directory
+     */
+    public PlatformExporter(File localFile) {
+        this.localParent = localFile;
+    }
+
+    /**
+     * Checks if 'prune-missing' is enabled.
+     * @return <code>true</code> if prune-missing is enabled
+     */
+    public boolean pruneMissing() {
+        return pruneMissing;
+    }
+
+    /**
+     * Sets the 'prune-missing' flag.
+     * @param pruneMissing the flag
+     */
+    public void setPruneMissing(boolean pruneMissing) {
+        this.pruneMissing = pruneMissing;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void open() throws IOException, RepositoryException {
+        scan(new File(localParent, Constants.ROOT_DIR));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void close() throws IOException {
+        if (pruneMissing) {
+            for (ExportInfo.Entry e: exportInfo.getEntries().values()) {
+                if (e.type == ExportInfo.Type.DELETE) {
+                    File file = new File(e.path);
+                    FileUtils.deleteQuietly(file);
+                    track("D", PathUtil.getRelativePath(localParent.getAbsolutePath(), e.path));
+                }
+            }
+        }
+    }
+
+    private void scan(File dir) throws IOException {
+        File[] files = dir.listFiles();
+        if (files == null) {
+            return;
+        }
+        for (File file: files) {
+            String name = file.getName();
+            if (name.equals(".svn") || name.equals(".vlt")) {
+                continue;
+            }
+            if (file.isDirectory()) {
+                exportInfo.update(ExportInfo.Type.RMDIR, file.getPath());
+                scan(file);
+            } else {
+                exportInfo.update(ExportInfo.Type.DELETE, file.getPath());
+            }
+        }
+    }
+
+    public void createDirectory(VaultFile file, String relPath)
+            throws RepositoryException, IOException {
+        File dir = new File(localParent, getPlatformFilePath(file, relPath));
+        mkdirs(dir);
+        track("A", PathUtil.getRelativeFilePath(localParent.getAbsolutePath(), dir.getAbsolutePath()));
+    }
+
+    public void createDirectory(String relPath) throws IOException {
+        File dir = new File(localParent, relPath);
+        mkdirs(dir);
+    }
+
+    public void writeFile(VaultFile file, String relPath)
+            throws RepositoryException, IOException {
+        File local = new File(localParent, getPlatformFilePath(file, relPath));
+        if (!local.getParentFile().exists()) {
+            mkdirs(local.getParentFile());
+        }
+        if (local.exists()) {
+            exportInfo.update(ExportInfo.Type.UPDATE, local.getPath());
+        } else {
+            exportInfo.update(ExportInfo.Type.ADD, local.getPath());
+        }
+        track("A", PathUtil.getRelativeFilePath(localParent.getAbsolutePath(), local.getAbsolutePath()));
+        Artifact a = file.getArtifact();
+        switch (a.getPreferredAccess()) {
+            case NONE:
+                throw new RepositoryException("Artifact has no content.");
+
+            case SPOOL:
+                FileOutputStream out = new FileOutputStream(local);
+                a.spool(out);
+                out.close();
+                break;
+
+            case STREAM:
+                InputStream in = a.getInputStream();
+                out = new FileOutputStream(local);
+                IOUtils.copy(in, out);
+                in.close();
+                out.close();
+                break;
+        }
+        if (a.getLastModified() >= 0) {
+            local.setLastModified(a.getLastModified());
+        }
+    }
+
+    public void writeFile(InputStream in, String relPath) throws IOException {
+        File local = new File(localParent, relPath);
+        if (!local.getParentFile().exists()) {
+            mkdirs(local.getParentFile());
+        }
+        if (local.exists()) {
+            exportInfo.update(ExportInfo.Type.UPDATE, local.getPath());
+        } else {
+            exportInfo.update(ExportInfo.Type.ADD, local.getPath());
+        }
+        OutputStream out = new FileOutputStream(local);
+        IOUtils.copy(in, out);
+        in.close();
+        out.close();
+    }
+
+    private void mkdirs(File dir) throws IOException {
+        dir.mkdirs();
+        exportInfo.update(ExportInfo.Type.MKDIR, dir.getPath());
+    }
+
+}
\ No newline at end of file

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/Serializer.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/Serializer.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/Serializer.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/Serializer.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,36 @@
+/*
+ * 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.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.vault.fs.api.SerializationType;
+
+/**
+ * <code>Serializer</code>...
+ *
+ */
+public interface Serializer {
+
+    public void writeContent(OutputStream out) throws IOException, RepositoryException;
+
+    public SerializationType getType();
+}
\ No newline at end of file

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/SubArchive.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/SubArchive.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/SubArchive.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/SubArchive.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,80 @@
+/*
+ * 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.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.jackrabbit.vault.fs.api.VaultInputSource;
+import org.apache.jackrabbit.vault.fs.config.DefaultMetaInf;
+import org.apache.jackrabbit.vault.fs.config.MetaInf;
+
+/**
+ * <code>SubArchive</code>...
+ */
+public class SubArchive extends AbstractArchive {
+
+    private Archive base;
+
+    private Entry root;
+
+    private final boolean isJcrRoot;
+
+    private DefaultMetaInf inf = new DefaultMetaInf();
+
+    public SubArchive(Archive base, Entry root, boolean isJcrRoot) {
+        this.base = base;
+        this.root = root;
+        this.isJcrRoot = isJcrRoot;
+        inf.setSettings(base.getMetaInf().getSettings());
+        inf.setConfig(base.getMetaInf().getConfig());
+    }
+
+    public Entry getRoot() throws IOException {
+        return root;
+    }
+
+    @Override
+    public Entry getJcrRoot() throws IOException {
+        if (isJcrRoot) {
+            return root;
+        } else {
+            return super.getJcrRoot();
+        }
+    }
+
+    public void open(boolean strict) throws IOException {
+        // assume open
+    }
+
+    public MetaInf getMetaInf() {
+        return inf;
+    }
+
+    public void close() {
+        base = null;
+    }
+
+    public InputStream openInputStream(Entry entry) throws IOException {
+        return base.openInputStream(entry);
+    }
+
+    public VaultInputSource getInputSource(Entry entry) throws IOException {
+        return base.getInputSource(entry);
+    }
+}
\ No newline at end of file

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/ZipArchive.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/ZipArchive.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/ZipArchive.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/ZipArchive.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,222 @@
+/*
+ * 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.io;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipInputStream;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.io.input.CloseShieldInputStream;
+import org.apache.jackrabbit.vault.fs.api.VaultInputSource;
+import org.apache.jackrabbit.vault.fs.config.ConfigurationException;
+import org.apache.jackrabbit.vault.fs.config.DefaultMetaInf;
+import org.apache.jackrabbit.vault.fs.config.MetaInf;
+import org.apache.jackrabbit.vault.fs.config.VaultSettings;
+import org.apache.jackrabbit.vault.fs.spi.CNDReader;
+import org.apache.jackrabbit.vault.fs.spi.ServiceProviderFactory;
+import org.apache.jackrabbit.vault.util.Constants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The zip archive implements bridge between the ZipStreamArchive and the
+ * ZipFileArchive. the former is needed due to a bug in ZipFile of jdk1.5 that
+ * causes problems with zip files with a lot of entries.
+ */
+public class ZipArchive extends AbstractArchive {
+
+    /**
+     * default logger
+     */
+    private static final Logger log = LoggerFactory.getLogger(ZipArchive.class);
+
+    private DefaultMetaInf inf;
+
+    private int numEntries;
+
+    private Archive base;
+
+    private final File zipFile;
+
+    public ZipArchive(File zipFile) {
+        this.zipFile = zipFile;
+    }
+
+
+    public void open(boolean strict) throws IOException {
+        if (inf != null) {
+            throw new IllegalStateException("already open.");
+        }
+        // first load the meta info and count the entries
+        ZipInputStream zin = new ZipInputStream(
+                new BufferedInputStream(
+                        new FileInputStream(zipFile)
+                )
+        );
+        numEntries = 0;
+        inf = new DefaultMetaInf();
+        try {
+            ZipEntry entry;
+            while ((entry = zin.getNextEntry()) != null) {
+                numEntries++;
+                String name = entry.getName();
+
+                // check for meta inf
+                if (!name.startsWith(Constants.META_DIR + "/")) {
+                    continue;
+                }
+                String path = zipFile.getPath() + ":" + name;
+                name = name.substring((Constants.META_DIR + "/").length());
+                if (name.equals(Constants.FILTER_XML)) {
+                    // load filter
+                    inf.loadFilter(new CloseShieldInputStream(zin), path);
+                } else if (name.equals(Constants.CONFIG_XML)) {
+                    // load config
+                    inf.loadConfig(new CloseShieldInputStream(zin), path);
+                } else if (name.equals(Constants.SETTINGS_XML)) {
+                    // load settings
+                    inf.loadSettings(new CloseShieldInputStream(zin), path);
+                } else if (name.equals(Constants.PROPERTIES_XML)) {
+                    // load properties
+                    inf.loadProperties(new CloseShieldInputStream(zin), path);
+                } else if (name.equals(Constants.PRIVILEGES_XML)) {
+                    // load privileges
+                    inf.loadPrivileges(new CloseShieldInputStream(zin), path);
+                } else if (name.equals(Constants.PACKAGE_DEFINITION_XML)) {
+                    inf.setHasDefinition(true);
+                    log.debug("Contains package definition {}.", path);
+                } else if (name.endsWith(".cnd")) {
+                    try {
+                        Reader r = new InputStreamReader(new CloseShieldInputStream(zin), "utf8");
+                        CNDReader reader = ServiceProviderFactory.getProvider().getCNDReader();
+                        reader.read(r, entry.getName(), null);
+                        inf.getNodeTypes().add(reader);
+                        log.debug("Loaded nodetypes from {}.", path);
+                    } catch (IOException e1) {
+                        log.error("Error while reading CND: {}", e1.toString());
+                        if (strict) {
+                            throw e1;
+                        }
+                    }
+                }
+            }
+            if (inf.getFilter() == null) {
+                log.debug("Zip {} does not contain filter definition.", zipFile.getPath());
+            }
+            if (inf.getConfig() == null) {
+                log.debug("Zip {} does not contain vault config.", zipFile.getPath());
+            }
+            if (inf.getSettings() == null) {
+                log.debug("Zip {} does not contain vault settings. using default.", zipFile.getPath());
+                VaultSettings settings = new VaultSettings();
+                settings.getIgnoredNames().add(".svn");
+                inf.setSettings(settings);
+            }
+            if (inf.getProperties() == null) {
+                log.debug("Zip {} does not contain properties.", zipFile.getPath());
+            }
+            if (inf.getNodeTypes().isEmpty()) {
+                log.debug("Zip {} does not contain nodetypes.", zipFile.getPath());
+            }
+
+        } catch (IOException e) {
+            log.error("Error while loading zip {}.", zipFile.getPath());
+            throw e;
+        } catch (ConfigurationException e) {
+            log.error("Error while loading zip {}.", zipFile.getPath());
+            IOException io = new IOException(e.toString());
+            io.initCause(e);
+            throw io;
+        } finally {
+            IOUtils.closeQuietly(zin);
+        }
+
+    }
+
+    private Archive getBase() throws IOException {
+        if (inf == null) {
+            throw new IOException("Archive not open.");
+        }
+        if (base == null) {
+            // zip file only supports sizes up to 2GB
+            if (zipFile.length() > (long) Integer.MAX_VALUE) {
+                log.warn("ZipFile is larger than 2GB. Fallback to streaming archive.");
+            } else {
+                // check if the zip file provides the correct size (# entries)
+                ZipFile zip = new ZipFile(zipFile, ZipFile.OPEN_READ);
+                if (zip.size() != numEntries) {
+                    log.warn("ZipFile reports {} entries, but stream counts {} entries. " +
+                            "Fallback to streaming archive.",
+                            String.valueOf(zip.size()), String.valueOf(numEntries));
+                    try {
+                        zip.close();
+                    } catch (IOException e) {
+                        // ignore
+                    }
+                } else {
+                    base = new ZipFileArchive(zip);
+                }
+            }
+            if (base == null) {
+                base = new ZipStreamArchive(zipFile);
+            }
+            base.open(false);
+        }
+        return base;
+    }
+
+    public MetaInf getMetaInf() {
+        if (inf == null) {
+            throw new IllegalStateException("Archive not open.");
+        }
+        return inf;
+    }
+
+    public InputStream openInputStream(Entry entry) throws IOException {
+        return getBase().openInputStream(entry);
+    }
+
+    public VaultInputSource getInputSource(Entry entry) throws IOException {
+        return getBase().getInputSource(entry);
+    }
+
+    public Entry getRoot() throws IOException {
+        return getBase().getRoot();
+    }
+
+    public void close() {
+        if (base != null) {
+            base.close();
+            base = null;
+        }
+        inf = null;
+    }
+
+    @Override
+    public String toString() {
+        return zipFile.getPath();
+    }
+}
\ No newline at end of file

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/ZipFileArchive.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/ZipFileArchive.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/ZipFileArchive.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/ZipFileArchive.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,200 @@
+/*
+ * 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.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import org.apache.jackrabbit.vault.fs.api.VaultInputSource;
+import org.apache.jackrabbit.vault.fs.config.MetaInf;
+import org.apache.jackrabbit.vault.util.Text;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implements an archive that is based on a zip file.
+ */
+class ZipFileArchive extends AbstractArchive {
+
+    /**
+     * default logger
+     */
+    private static final Logger log = LoggerFactory.getLogger(ZipFileArchive.class);
+
+    private ZipFile zip;
+
+    private JarEntry root;
+
+    public ZipFileArchive(ZipFile zip) {
+        this.zip = zip;
+    }
+
+    public void open(boolean strict) throws IOException {
+        root = new JarEntry("", true);
+        Enumeration e = zip.entries();
+        while (e.hasMoreElements()) {
+            ZipEntry entry = (ZipEntry) e.nextElement();
+            String path = entry.getName();
+            String[] names = Text.explode(path, '/');
+            if (names.length > 0) {
+                JarEntry je = root;
+                for (int i=0; i<names.length; i++) {
+                    if (i == names.length -1) {
+                        je = je.add(names[i], entry.isDirectory());
+                    } else {
+                        je = je.add(names[i], true);
+                    }
+                }
+                je.zipEntryName = entry.getName();
+                log.debug("scanning jar: {}", je.zipEntryName);
+            }
+        }
+    }
+
+
+    public InputStream openInputStream(Entry entry) throws IOException {
+        JarEntry e = (JarEntry) entry;
+        if (e == null || e.zipEntryName == null) {
+            return null;
+        }
+        ZipEntry ze = zip.getEntry(e.zipEntryName);
+        if (ze == null) {
+            throw new IOException("ZipEntry could not be found: " + e.zipEntryName);
+        }
+        return zip.getInputStream(ze);
+    }
+
+    public VaultInputSource getInputSource(Entry entry) throws IOException {
+        JarEntry e = (JarEntry) entry;
+        if (e == null || e.zipEntryName == null) {
+            return null;
+        }
+        final ZipEntry ze = zip.getEntry(e.zipEntryName);
+        if (ze == null) {
+            throw new IOException("ZipEntry could not be found: " + e.zipEntryName);
+        }
+        return new VaultInputSource() {
+
+            {
+                setSystemId(ze.getName());
+            }
+
+            public InputStream getByteStream() {
+                try {
+                    return zip.getInputStream(ze);
+                } catch (IOException e1) {
+                    return null;
+                }
+            }
+
+            /**
+             * {@inheritDoc}
+             */
+            public long getContentLength() {
+                return ze.getSize();
+            }
+
+            /**
+             * {@inheritDoc}
+             */
+            public long getLastModified() {
+                return ze.getTime();
+            }
+
+        };
+    }
+
+    public void close() {
+        try {
+            if (zip != null) {
+                zip.close();
+                zip = null;
+            }
+        } catch (IOException e) {
+            log.warn("Error during close.", e);
+        }
+    }
+
+    public Entry getRoot() throws IOException {
+        return root;
+    }
+
+    public MetaInf getMetaInf() {
+        throw new IllegalStateException("getMetaInf() should not be called directly.");
+    }
+
+    private static class JarEntry implements Entry {
+
+        public final String name;
+
+        private String zipEntryName;
+
+        public final boolean isDirectory;
+
+        public Map<String, JarEntry> children;
+
+        public JarEntry(String name, boolean directory) {
+            this.name = name;
+            isDirectory = directory;
+        }
+
+        public JarEntry add(String name, boolean isDirectory) {
+            if (children != null) {
+                JarEntry ret = children.get(name);
+                if (ret != null) {
+                    return ret;
+                }
+            }
+            return add(new JarEntry(name, isDirectory));
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public boolean isDirectory() {
+            return isDirectory;
+        }
+
+        public JarEntry add(JarEntry e) {
+            if (children == null) {
+                children = new LinkedHashMap<String, JarEntry>();
+            }
+            children.put(e.getName(), e);
+            return e;
+        }
+
+        public Collection<? extends Entry> getChildren() {
+            return children == null
+                    ? Collections.<JarEntry>emptyList()
+                    : children.values();
+        }
+
+        public Entry getChild(String name) {
+            return children == null ? null : children.get(name);
+        }
+
+    }
+}
\ No newline at end of file

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/ZipStreamArchive.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/ZipStreamArchive.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/ZipStreamArchive.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/ZipStreamArchive.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,319 @@
+/*
+ * 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.io;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.RandomAccessFile;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.jackrabbit.vault.fs.api.VaultInputSource;
+import org.apache.jackrabbit.vault.fs.config.MetaInf;
+import org.apache.jackrabbit.vault.util.Text;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implements an archive based on a zip file, but deflates the entries first
+ * in a tmp file. this is only used to circumvent a bug in ZipFile of jdk1.5,
+ * that has problems with large zip files.
+ */
+class ZipStreamArchive extends AbstractArchive {
+
+    /**
+     * default logger
+     */
+    private static final Logger log = LoggerFactory.getLogger(ZipStreamArchive.class);
+
+    private final File zipFile;
+
+    private File tmpFile;
+
+    private RandomAccessFile raf;
+
+    private JarEntry root;
+
+    public ZipStreamArchive(File zipFile) {
+        this.zipFile = zipFile;
+    }
+
+    public void open(boolean strict) throws IOException {
+        if (raf != null) {
+            throw new IllegalStateException("already open");
+        }
+
+        tmpFile = File.createTempFile("__vlttmpbuffer", ".dat");
+        raf = new RandomAccessFile(tmpFile, "rw");
+
+        root = new JarEntry("");
+
+        // scan the zip and copy data to temporary file
+        ZipInputStream zin = new ZipInputStream(
+                new BufferedInputStream(
+                        new FileInputStream(zipFile)
+                )
+        );
+
+        try {
+            ZipEntry entry;
+            while ((entry = zin.getNextEntry()) != null) {
+                String name = entry.getName();
+                String[] names = Text.explode(name, '/');
+                if (names.length > 0) {
+                    JarEntry je = root;
+                    for (int i=0; i<names.length; i++) {
+                        if (i == names.length -1 && !entry.isDirectory()) {
+                            // copy stream
+                            long pos = raf.getFilePointer();
+                            long len = copy(zin);
+                            je = je.add(new JarEntry(names[i], entry.getTime(), pos, len));
+                        } else {
+                            je = je.add(names[i]);
+                        }
+                    }
+                    if (log.isDebugEnabled()) {
+                        log.debug("scanning jar: {}", name);
+                    }
+                }
+            }
+        } finally {
+            IOUtils.closeQuietly(zin);
+        }
+    }
+
+    private long copy(InputStream in) throws IOException {
+        byte[] buffer = new byte[8192];
+        int read;
+        int total = 0;
+        while ((read = in.read(buffer)) > 0) {
+            raf.write(buffer, 0, read);
+            total += read;
+        }
+        return total;
+    }
+
+    public InputStream openInputStream(Entry entry) throws IOException {
+        return new RafInputStream((JarEntry) entry);
+    }
+
+    public VaultInputSource getInputSource(Entry entry) throws IOException {
+        return new RafInputSource((JarEntry) entry);
+    }
+
+    public MetaInf getMetaInf() {
+        throw new IllegalStateException("getMetaInf() should not be called directly.");
+    }
+
+    public void close() {
+        if (raf != null) {
+            try {
+                raf.close();
+            } catch (IOException e) {
+                // ignore
+            }
+            raf = null;
+        }
+        if (tmpFile != null) {
+            FileUtils.deleteQuietly(tmpFile);
+            tmpFile = null;
+        }
+    }
+
+    public Entry getRoot() throws IOException {
+        return root;
+    }
+
+    private class RafInputSource extends VaultInputSource {
+
+        private final JarEntry entry;
+
+        private RafInputSource(JarEntry entry) {
+            this.entry = entry;
+        }
+
+        @Override
+        public InputStream getByteStream() {
+            return new RafInputStream(entry);
+        }
+
+        public long getContentLength() {
+            return entry.len;
+        }
+
+        public long getLastModified() {
+            return entry.date;
+        }
+    }
+
+    private class RafInputStream extends InputStream {
+
+        private long pos;
+
+        private long end;
+
+        private long mark;
+
+        private RafInputStream(JarEntry entry) {
+            pos = entry.pos;
+            end = pos + entry.len;
+        }
+
+        public int read() throws IOException {
+            if (pos < end) {
+                raf.seek(pos++);
+                return raf.read();
+            } else {
+                return -1;
+            }
+        }
+
+        @Override
+        public int read(byte[] b, int off, int len) throws IOException {
+            if (pos >= end) {
+                return -1;
+            }
+            len = Math.min(len, (int) (end-pos));
+            raf.seek(pos);
+            int read = raf.read(b, off, len);
+            if (read < 0) {
+                return -1;
+            }
+            pos += read;
+            return read;
+        }
+
+        @Override
+        public int read(byte[] b) throws IOException {
+            return read(b, 0, b.length);
+        }
+
+        @Override
+        public long skip(long n) throws IOException {
+            if (pos >= end) {
+                return -1;
+            }
+            n = Math.min(n, end - pos);
+            pos+= n;
+            return n;
+        }
+
+        @Override
+        public int available() throws IOException {
+            return (int) (end - pos);
+        }
+
+        @Override
+        public void close() throws IOException {
+            // ignore
+        }
+
+        @Override
+        public void mark(int readlimit) {
+            mark = pos;
+        }
+
+        @Override
+        public void reset() throws IOException {
+            pos = mark;
+        }
+
+        @Override
+        public boolean markSupported() {
+            return true;
+        }
+    }
+
+    private static class JarEntry implements Entry {
+
+        public final String name;
+
+        public final long date;
+
+        public final long pos;
+
+        public final long len;
+
+        public Map<String, JarEntry> children;
+
+        private JarEntry(String name) {
+            this.name = name;
+            this.date = 0;
+            pos = -1;
+            len = 0;
+        }
+
+        private JarEntry(String name, long date, long pos, long len) {
+            this.name = name;
+            this.date = date;
+            this.pos = pos;
+            this.len = len;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public boolean isDirectory() {
+            return pos < 0;
+        }
+
+        public JarEntry add(JarEntry e) {
+            if (children == null) {
+                children = new LinkedHashMap<String, JarEntry>();
+            }
+            children.put(e.getName(), e);
+            return e;
+        }
+
+        public JarEntry add(String name) {
+            JarEntry e;
+            if (children == null) {
+                children = new LinkedHashMap<String, JarEntry>();
+            } else {
+                e = children.get(name);
+                if (e != null) {
+                    return e;
+                }
+            }
+            e = new JarEntry(name);
+            children.put(name, e);
+            return e;
+        }
+
+        public Collection<? extends Entry> getChildren() {
+            return children == null
+                    ? Collections.<JarEntry>emptyList()
+                    : children.values();
+        }
+
+        public Entry getChild(String name) {
+            return children == null ? null : children.get(name);
+        }
+
+    }
+}
\ No newline at end of file

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/ACLManagement.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/ACLManagement.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/ACLManagement.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/ACLManagement.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,69 @@
+/*
+ * 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.spi;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+/**
+ * <code>AccessControlManagement</code>...
+ */
+public interface ACLManagement {
+
+    /**
+     * Checks if the given node type name is used for ACLs
+     * @param name the node type name
+     * @return <code>true</code> if used for ACLs
+     */
+    boolean isACLNodeType(String name);
+
+    /**
+     * Checks if the given node type name is use as access controllable
+     * mixin.
+     * @param name the node type name
+     * @return <code>true</code> if the name is the mixin name
+     */
+    boolean isAccessControllableMixin(String name);
+
+
+    /**
+     * Checks if the given node is an ACL node.
+     * @param node the node
+     * @return <code>true</code> if it's an ACL node.
+     * @throws RepositoryException if an error occurs
+     */
+    boolean isACLNode(Node node) throws RepositoryException;
+
+    /**
+     * Checks if the given node is access controllable, i.e. has the respective
+     * mixin and adds it if missing.
+     *
+     * @param node the node to check
+     * @return <code>true</code> if was made access controllable
+     * @throws RepositoryException if an error occurs
+     */
+    boolean ensureAccessControllable(Node node) throws RepositoryException;
+
+    /**
+     * Removes all ACLs from the given node.
+     *
+     * @param node the node
+     * @throws RepositoryException if an error occurs
+     */
+    void clearACL(Node node) throws RepositoryException;
+}
\ No newline at end of file

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/CNDReader.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/CNDReader.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/CNDReader.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/CNDReader.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,33 @@
+/*
+ * 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.spi;
+
+import java.io.IOException;
+import java.io.Reader;
+
+import org.apache.jackrabbit.spi.commons.namespace.NamespaceMapping;
+
+/**
+ * <code>CNDReader</code>...
+ */
+public interface CNDReader extends NodeTypeSet {
+
+    void read(Reader reader, String systemId, NamespaceMapping namespaceMapping)
+            throws IOException;
+
+}
\ No newline at end of file

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/CNDWriter.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/CNDWriter.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/CNDWriter.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/CNDWriter.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,41 @@
+/*
+ * 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.spi;
+
+import java.io.IOException;
+import java.util.Collection;
+
+import javax.jcr.nodetype.NodeType;
+
+import org.apache.jackrabbit.spi.QNodeTypeDefinition;
+
+/**
+ * Generic interface for a CND writer.
+ */
+public interface CNDWriter {
+
+    void write(QNodeTypeDefinition nt) throws IOException;
+
+    void write(Collection<QNodeTypeDefinition> nts) throws IOException;
+
+    void write(NodeType nt) throws IOException;
+
+    void close() throws IOException;
+
+
+}
\ No newline at end of file

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/DefaultNodeTypeSet.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/DefaultNodeTypeSet.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/DefaultNodeTypeSet.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/DefaultNodeTypeSet.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,137 @@
+/*
+ * 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.spi;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.TreeMap;
+
+import javax.jcr.NamespaceException;
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.QNodeTypeDefinition;
+import org.apache.jackrabbit.spi.commons.namespace.NamespaceMapping;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ */
+public class DefaultNodeTypeSet implements NodeTypeSet {
+
+    /**
+     * default logger
+     */
+    private static final Logger log = LoggerFactory.getLogger(DefaultNodeTypeSet.class);
+
+    private String systemId;
+
+    /**
+     * the list of nodetype templates
+     */
+    private Map<Name, QNodeTypeDefinition> nodeTypes =
+            new TreeMap<Name, QNodeTypeDefinition>();
+
+    /**
+     * the current namespace mapping
+     */
+    private NamespaceMapping nsMapping = new NamespaceMapping();
+
+    /**
+     * the list of removed nodetype templates
+     */
+    private Map<Name, QNodeTypeDefinition> removed =
+            new TreeMap<Name, QNodeTypeDefinition>();
+
+
+    public DefaultNodeTypeSet(String systemId) {
+        this.systemId = systemId;
+    }
+
+    public DefaultNodeTypeSet(NodeTypeSet set) {
+        this(set.getSystemId(), set.getNodeTypes().values(), set.getNamespaceMapping());
+    }
+
+    public DefaultNodeTypeSet(String systemId,
+                              Collection<QNodeTypeDefinition> nodeTypes,
+                              NamespaceMapping nsMapping) {
+        this.systemId = systemId;
+        for (QNodeTypeDefinition t: nodeTypes) {
+            this.nodeTypes.put(t.getName(), t);
+        }
+        this.nsMapping = nsMapping;
+    }
+
+    public void add(NodeTypeSet set) {
+        for (QNodeTypeDefinition tpl: set.getNodeTypes().values()) {
+            log.debug("adding {}", tpl.getName());
+            nodeTypes.put(tpl.getName(), tpl);
+        }
+        add(set.getNamespaceMapping());
+    }
+
+    public void add(Collection<QNodeTypeDefinition> set, NamespaceMapping nsMapping) {
+        for (QNodeTypeDefinition tpl: set) {
+            log.debug("adding {}", tpl.getName());
+            nodeTypes.put(tpl.getName(), tpl);
+        }
+        add(nsMapping);
+    }
+
+    private void add(NamespaceMapping mapping) {
+        for (Object o : mapping.getPrefixToURIMapping().keySet()) {
+            try {
+                String pfx = (String) o;
+                String uri = mapping.getURI(pfx);
+                nsMapping.setMapping(pfx, uri);
+            } catch (NamespaceException e) {
+                throw new IllegalStateException("Error while transfering mappings.", e);
+            }
+        }
+    }
+
+    public QNodeTypeDefinition remove(Name name)
+            throws RepositoryException {
+        QNodeTypeDefinition tpl = nodeTypes.remove(name);
+        if (tpl != null) {
+            removed.put(tpl.getName(), tpl);
+            log.debug("removing registered {}", tpl.getName());
+        }
+        return tpl;
+    }
+
+    public Map<Name, QNodeTypeDefinition> getNodeTypes() {
+        return nodeTypes;
+    }
+
+    public NamespaceMapping getNamespaceMapping() {
+        return nsMapping;
+    }
+
+    public Map<Name, QNodeTypeDefinition> getRemoved() {
+        return removed;
+    }
+
+    public String getSystemId() {
+        return systemId;
+    }
+
+    public void setSystemId(String systemId) {
+        this.systemId = systemId;
+    }
+}
\ No newline at end of file

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/DefaultNodeTypes.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/DefaultNodeTypes.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/DefaultNodeTypes.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/DefaultNodeTypes.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,161 @@
+/*
+ * 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.spi;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * <code>DefaultNodeTypes</code>...
+ */
+public final class DefaultNodeTypes {
+
+    public static final Set<String> JSR170_NODE_TYPES = new HashSet<String>();
+
+    static {
+        JSR170_NODE_TYPES.add("nt:base");
+        JSR170_NODE_TYPES.add("nt:unstructured");
+        JSR170_NODE_TYPES.add("mix:referenceable");
+        JSR170_NODE_TYPES.add("mix:lockable");
+        JSR170_NODE_TYPES.add("mix:versionable");
+        JSR170_NODE_TYPES.add("nt:versionHistory");
+        JSR170_NODE_TYPES.add("nt:versionLabels");
+        JSR170_NODE_TYPES.add("nt:version");
+        JSR170_NODE_TYPES.add("nt:frozenNode");
+        JSR170_NODE_TYPES.add("nt:versionedChild");
+        JSR170_NODE_TYPES.add("nt:nodeType");
+        JSR170_NODE_TYPES.add("nt:propertyDefinition");
+        JSR170_NODE_TYPES.add("nt:childNodeDefinition");
+        JSR170_NODE_TYPES.add("nt:hierarchyNode");
+        JSR170_NODE_TYPES.add("nt:folder");
+        JSR170_NODE_TYPES.add("nt:file");
+        JSR170_NODE_TYPES.add("nt:linkedFile");
+        JSR170_NODE_TYPES.add("nt:resource");
+        JSR170_NODE_TYPES.add("nt:query");
+    }
+
+    public static final Set<String> JSR283_NODE_TYPES = new HashSet<String>(JSR170_NODE_TYPES);
+
+    static {
+        JSR283_NODE_TYPES.add("mix:created");
+        JSR283_NODE_TYPES.add("mix:lastModified");
+        JSR283_NODE_TYPES.add("mix:etag");
+        JSR283_NODE_TYPES.add("mix:title");
+        JSR283_NODE_TYPES.add("mix:language");
+        JSR283_NODE_TYPES.add("mix:mimeType");
+        JSR283_NODE_TYPES.add("mix:shareable");
+        JSR283_NODE_TYPES.add("mix:simpleVersionable");
+        JSR283_NODE_TYPES.add("mix:lifecycle");
+        JSR283_NODE_TYPES.add("nt:address");
+        JSR283_NODE_TYPES.add("nt:activity");
+        JSR283_NODE_TYPES.add("nt:configuration");
+    }
+
+    public static final Set<String> JACKRABBIT_1X_NODE_TYPES = new HashSet<String>(JSR170_NODE_TYPES);
+
+    static {
+        JACKRABBIT_1X_NODE_TYPES.add("rep:nodeTypes");
+        JACKRABBIT_1X_NODE_TYPES.add("rep:root");
+        JACKRABBIT_1X_NODE_TYPES.add("rep:system");
+        JACKRABBIT_1X_NODE_TYPES.add("rep:versionStorage");
+    }
+
+    public static final Set<String> JACKRABBIT_2X_NODE_TYPES = new HashSet<String>(JSR283_NODE_TYPES);
+
+    static {
+        JACKRABBIT_2X_NODE_TYPES.add("rep:nodeTypes");
+        JACKRABBIT_2X_NODE_TYPES.add("rep:root");
+        JACKRABBIT_2X_NODE_TYPES.add("rep:system");
+        JACKRABBIT_2X_NODE_TYPES.add("rep:versionStorage");
+        // since 2.0
+        JACKRABBIT_2X_NODE_TYPES.add("rep:Activities");
+        JACKRABBIT_2X_NODE_TYPES.add("rep:Configurations");
+        JACKRABBIT_2X_NODE_TYPES.add("rep:VersionReference");
+        JACKRABBIT_2X_NODE_TYPES.add("rep:AccessControllable");
+        JACKRABBIT_2X_NODE_TYPES.add("rep:Policy");
+        JACKRABBIT_2X_NODE_TYPES.add("rep:ACL");
+        JACKRABBIT_2X_NODE_TYPES.add("rep:ACE");
+        JACKRABBIT_2X_NODE_TYPES.add("rep:GrantACE");
+        JACKRABBIT_2X_NODE_TYPES.add("rep:DenyACE");
+        JACKRABBIT_2X_NODE_TYPES.add("rep:AccessControl");
+        JACKRABBIT_2X_NODE_TYPES.add("rep:PrincipalAccessControl");
+        JACKRABBIT_2X_NODE_TYPES.add("rep:Authorizable");
+        JACKRABBIT_2X_NODE_TYPES.add("rep:Impersonatable");
+        JACKRABBIT_2X_NODE_TYPES.add("rep:User");
+        JACKRABBIT_2X_NODE_TYPES.add("rep:Group");
+        JACKRABBIT_2X_NODE_TYPES.add("rep:AuthorizableFolder");
+        JACKRABBIT_2X_NODE_TYPES.add("rep:RetentionManageable");
+    }
+
+    public static final Set<String> CRX_1X_NODE_TYPES = new HashSet<String>(JACKRABBIT_1X_NODE_TYPES);
+
+    static {
+        CRX_1X_NODE_TYPES.add("crx:XmlNode");
+        CRX_1X_NODE_TYPES.add("crx:XmlCharacterData");
+        CRX_1X_NODE_TYPES.add("crx:XmlElement");
+        CRX_1X_NODE_TYPES.add("crx:XmlDocument");
+        CRX_1X_NODE_TYPES.add("crx:XmlProcessingInstruction");
+        CRX_1X_NODE_TYPES.add("crx:Package");
+        CRX_1X_NODE_TYPES.add("crx:ItemFilter");
+        CRX_1X_NODE_TYPES.add("crx:HierarchyFilter");
+        CRX_1X_NODE_TYPES.add("crx:OPVValueFilter");
+        CRX_1X_NODE_TYPES.add("crx:DeclaredTypeFilter");
+        CRX_1X_NODE_TYPES.add("crx:NodeTypeFilter");
+        CRX_1X_NODE_TYPES.add("crx:XPathFilter");
+        CRX_1X_NODE_TYPES.add("rep:AccessControllable");
+        CRX_1X_NODE_TYPES.add("rep:AccessControl");
+        CRX_1X_NODE_TYPES.add("rep:Permission");
+        CRX_1X_NODE_TYPES.add("rep:GrantPermission");
+        CRX_1X_NODE_TYPES.add("rep:DenyPermission");
+        CRX_1X_NODE_TYPES.add("rep:Principal");
+        CRX_1X_NODE_TYPES.add("rep:Impersonateable");
+        CRX_1X_NODE_TYPES.add("rep:User");
+        CRX_1X_NODE_TYPES.add("rep:Group");
+        CRX_1X_NODE_TYPES.add("rep:PrincipalFolder");
+        CRX_1X_NODE_TYPES.add("rep:ExternalPrincipal");
+        CRX_1X_NODE_TYPES.add("rep:Sudoers");
+        CRX_1X_NODE_TYPES.add("rep:WorkspaceAccess");
+        CRX_1X_NODE_TYPES.add("rep:Workspace");
+        CRX_1X_NODE_TYPES.add("crx:ResourceBundle");
+        CRX_1X_NODE_TYPES.add("crx:RequestMapping");
+        CRX_1X_NODE_TYPES.add("crx:NodeTypeRequestMapping");
+        CRX_1X_NODE_TYPES.add("crx:PathRequestMapping");
+    }
+
+    public static final Set<String> CRX_2X_NODE_TYPES = new HashSet<String>(JACKRABBIT_2X_NODE_TYPES);
+
+    static {
+        CRX_2X_NODE_TYPES.add("crx:XmlNode");
+        CRX_2X_NODE_TYPES.add("crx:XmlCharacterData");
+        CRX_2X_NODE_TYPES.add("crx:XmlElement");
+        CRX_2X_NODE_TYPES.add("crx:XmlDocument");
+        CRX_2X_NODE_TYPES.add("crx:XmlProcessingInstruction");
+        CRX_2X_NODE_TYPES.add("crx:Package");
+        CRX_2X_NODE_TYPES.add("crx:ItemFilter");
+        CRX_2X_NODE_TYPES.add("crx:HierarchyFilter");
+        CRX_2X_NODE_TYPES.add("crx:OPVValueFilter");
+        CRX_2X_NODE_TYPES.add("crx:DeclaredTypeFilter");
+        CRX_2X_NODE_TYPES.add("crx:NodeTypeFilter");
+        CRX_2X_NODE_TYPES.add("crx:XPathFilter");
+        CRX_2X_NODE_TYPES.add("crx:ResourceBundle");
+        CRX_2X_NODE_TYPES.add("crx:RequestMapping");
+        CRX_2X_NODE_TYPES.add("crx:NodeTypeRequestMapping");
+        CRX_2X_NODE_TYPES.add("crx:PathRequestMapping");
+    }
+
+}
\ No newline at end of file

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/JcrVersion.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/JcrVersion.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/JcrVersion.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/JcrVersion.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,34 @@
+/*
+ * 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.spi;
+
+/**
+ * Specifies the JCR Version
+ */
+public enum JcrVersion {
+
+    /**
+     * Version 1.0 (JSR170)
+     */
+    V10,
+
+    /**
+     * Version 2.0 (JCR283)
+     */
+    V20
+}

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/NodeTypeInstaller.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/NodeTypeInstaller.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/NodeTypeInstaller.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/NodeTypeInstaller.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,34 @@
+/*
+ * 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.spi;
+
+import java.io.IOException;
+import java.util.Collection;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NodeType;
+
+/**
+ * <code>NodeTypeInstaller</code>...
+ */
+public interface NodeTypeInstaller {
+
+    Collection<NodeType> install(ProgressTracker tracker, NodeTypeSet types)
+            throws IOException, RepositoryException;
+
+}
\ No newline at end of file

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/NodeTypeSet.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/NodeTypeSet.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/NodeTypeSet.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/NodeTypeSet.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,36 @@
+/*
+ * 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.spi;
+
+import java.util.Map;
+
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.QNodeTypeDefinition;
+import org.apache.jackrabbit.spi.commons.namespace.NamespaceMapping;
+
+/**
+ * Defines a generic set of node types.
+ */
+public interface NodeTypeSet {
+
+    Map<Name, QNodeTypeDefinition> getNodeTypes();
+
+    NamespaceMapping getNamespaceMapping();
+
+    String getSystemId();
+}
\ No newline at end of file

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/PrivilegeDefinitions.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/PrivilegeDefinitions.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/PrivilegeDefinitions.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/spi/PrivilegeDefinitions.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,42 @@
+/*
+ * 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.spi;
+
+import java.util.Collection;
+import java.util.LinkedList;
+
+import org.apache.jackrabbit.spi.PrivilegeDefinition;
+import org.apache.jackrabbit.spi.commons.namespace.NamespaceMapping;
+
+/**
+ * Defines a set of privilege definitions together with the used namespaces
+ */
+public class PrivilegeDefinitions {
+
+    private Collection<PrivilegeDefinition> defs = new LinkedList<PrivilegeDefinition>();
+
+    private NamespaceMapping mapping = new NamespaceMapping();
+
+    public Collection<PrivilegeDefinition> getDefinitions() {
+        return defs;
+    }
+
+    public NamespaceMapping getNamespaceMapping() {
+        return mapping;
+    }
+}
\ No newline at end of file