Package org.jboss.dna.connector.svn

Source Code of org.jboss.dna.connector.svn.SVNRepositoryRequestProcessor$AddFile

/*
* JBoss DNA (http://www.jboss.org/dna)
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.  Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
* See the AUTHORS.txt file in the distribution for a full listing of
* individual contributors.
*
* JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
* is licensed to you under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* JBoss DNA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.dna.connector.svn;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.jboss.dna.common.i18n.I18n;
import org.jboss.dna.common.util.Logger;
import org.jboss.dna.connector.scm.ScmAction;
import org.jboss.dna.connector.scm.ScmActionFactory;
import org.jboss.dna.graph.DnaLexicon;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.JcrLexicon;
import org.jboss.dna.graph.JcrNtLexicon;
import org.jboss.dna.graph.Location;
import org.jboss.dna.graph.connector.RepositorySourceException;
import org.jboss.dna.graph.property.Binary;
import org.jboss.dna.graph.property.BinaryFactory;
import org.jboss.dna.graph.property.DateTimeFactory;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.NameFactory;
import org.jboss.dna.graph.property.Path;
import org.jboss.dna.graph.property.PathFactory;
import org.jboss.dna.graph.property.PathNotFoundException;
import org.jboss.dna.graph.property.Property;
import org.jboss.dna.graph.property.PropertyFactory;
import org.jboss.dna.graph.property.ValueFactory;
import org.jboss.dna.graph.request.CloneBranchRequest;
import org.jboss.dna.graph.request.CloneWorkspaceRequest;
import org.jboss.dna.graph.request.CopyBranchRequest;
import org.jboss.dna.graph.request.CreateNodeRequest;
import org.jboss.dna.graph.request.CreateWorkspaceRequest;
import org.jboss.dna.graph.request.DeleteBranchRequest;
import org.jboss.dna.graph.request.DestroyWorkspaceRequest;
import org.jboss.dna.graph.request.GetWorkspacesRequest;
import org.jboss.dna.graph.request.InvalidRequestException;
import org.jboss.dna.graph.request.InvalidWorkspaceException;
import org.jboss.dna.graph.request.MoveBranchRequest;
import org.jboss.dna.graph.request.ReadAllChildrenRequest;
import org.jboss.dna.graph.request.ReadAllPropertiesRequest;
import org.jboss.dna.graph.request.ReadNodeRequest;
import org.jboss.dna.graph.request.RenameNodeRequest;
import org.jboss.dna.graph.request.Request;
import org.jboss.dna.graph.request.UpdatePropertiesRequest;
import org.jboss.dna.graph.request.VerifyWorkspaceRequest;
import org.jboss.dna.graph.request.processor.RequestProcessor;
import org.tmatesoft.svn.core.SVNDirEntry;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNNodeKind;
import org.tmatesoft.svn.core.SVNProperties;
import org.tmatesoft.svn.core.SVNProperty;
import org.tmatesoft.svn.core.io.ISVNEditor;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.io.diff.SVNDeltaGenerator;

/**
* The {@link RequestProcessor} implementation for the file subversion repository connector. This is the class that does the bulk
* of the work in the subversion repository connector, since it processes all requests.
*/
public class SVNRepositoryRequestProcessor extends RequestProcessor implements ScmActionFactory {

    protected static final String BACK_SLASH = "/";

    private static final String DEFAULT_MIME_TYPE = "application/octet-stream";

    private final String defaultNamespaceUri;
    private final boolean updatesAllowed;
    private SVNRepository defaultWorkspace;
    protected final Logger logger;
    private final Set<String> availableWorkspaceNames;
    private final boolean creatingWorkspacesAllowed;
    private final RepositoryAccessData accessData;

    /**
     * @param sourceName
     * @param context
     * @param defaultWorkspace
     * @param availableWorkspaceNames
     * @param creatingWorkspacesAllowed
     * @param updatesAllowed true if this connector supports updating the subversion repository, or false if the connector is read
     *        only
     * @param accessData
     */
    protected SVNRepositoryRequestProcessor( String sourceName,
                                             SVNRepository defaultWorkspace,
                                             Set<String> availableWorkspaceNames,
                                             boolean creatingWorkspacesAllowed,
                                             ExecutionContext context,
                                             boolean updatesAllowed,
                                             RepositoryAccessData accessData ) {
        super(sourceName, context, null);
        assert defaultWorkspace != null;
        assert availableWorkspaceNames != null;
        this.defaultNamespaceUri = getExecutionContext().getNamespaceRegistry().getDefaultNamespaceUri();
        this.updatesAllowed = updatesAllowed;
        this.defaultWorkspace = defaultWorkspace;
        this.logger = getExecutionContext().getLogger(getClass());
        this.availableWorkspaceNames = availableWorkspaceNames;
        this.creatingWorkspacesAllowed = creatingWorkspacesAllowed;
        this.accessData = accessData;
    }

    protected void addProperty( List<Property> properties,
                                PropertyFactory factory,
                                Name propertyName,
                                Object value ) {
        if (value != null) {
            properties.add(factory.create(propertyName, value));
        }
    }

    protected boolean readNode( String workspaceName,
                                Location myLocation,
                                List<Property> properties,
                                List<Location> children,
                                Request request ) {

        // Get the SVNRepository object that represents the workspace ...
        SVNRepository workspaceRoot = getWorkspaceDirectory(workspaceName);
        if (workspaceRoot == null) {
            request.setError(new InvalidWorkspaceException(SVNRepositoryConnectorI18n.workspaceDoesNotExist.text(workspaceName)));
            return false;
        }
        Path requestedPath = getPathFor(myLocation, request);
        checkThePath(requestedPath, request); // same-name-sibling indexes are not supported

        if (requestedPath.isRoot()) {
            // workspace root must be a directory
            if (children != null) {
                final Collection<SVNDirEntry> entries = SVNRepositoryUtil.getDir(workspaceRoot, "");
                for (SVNDirEntry entry : entries) {
                    // All of the children of a directory will be another directory or a file, but never a "jcr:content" node ...
                    String localName = entry.getName();
                    Name childName = nameFactory().create(defaultNamespaceUri, localName);
                    Path childPath = pathFactory().create(requestedPath, childName);
                    children.add(Location.create(childPath));
                }
            }
            // There are no properties on the root ...
        } else {
            try {
                // Generate the properties for this File object ...
                PropertyFactory factory = getExecutionContext().getPropertyFactory();
                DateTimeFactory dateFactory = getExecutionContext().getValueFactories().getDateFactory();

                // Figure out the kind of node this represents ...
                SVNNodeKind kind = getNodeKind(workspaceRoot, requestedPath, accessData.getRepositoryRootUrl(), workspaceName);
                if (kind == SVNNodeKind.DIR) {
                    String directoryPath = getPathAsString(requestedPath);
                    if (!accessData.getRepositoryRootUrl().equals(workspaceName)) {
                        directoryPath = directoryPath.substring(1);
                    }
                    if (children != null) {
                        // Decide how to represent the children ...
                        Collection<SVNDirEntry> dirEntries = SVNRepositoryUtil.getDir(workspaceRoot, directoryPath);
                        for (SVNDirEntry entry : dirEntries) {
                            // All of the children of a directory will be another directory or a file,
                            // but never a "jcr:content" node ...
                            String localName = entry.getName();
                            Name childName = nameFactory().create(defaultNamespaceUri, localName);
                            Path childPath = pathFactory().create(requestedPath, childName);
                            children.add(Location.create(childPath));
                        }
                    }
                    if (properties != null) {
                        // Load the properties for this directory ......
                        addProperty(properties, factory, JcrLexicon.PRIMARY_TYPE, JcrNtLexicon.FOLDER);
                        SVNDirEntry entry = getEntryInfo(workspaceRoot, directoryPath);
                        if (entry != null) {
                            addProperty(properties, factory, JcrLexicon.LAST_MODIFIED, dateFactory.create(entry.getDate()));
                        }
                    }
                } else {
                    // It's not a directory, so must be a file; the only child of an nt:file is the "jcr:content" node
                    // ...
                    if (requestedPath.endsWith(JcrLexicon.CONTENT)) {
                        // There are never any children of these nodes, just properties ...
                        if (properties != null) {
                            String contentPath = getPathAsString(requestedPath.getParent());
                            if (!accessData.getRepositoryRootUrl().equals(workspaceName)) {
                                contentPath = contentPath.substring(1);
                            }
                            SVNDirEntry entry = getEntryInfo(workspaceRoot, contentPath);
                            if (entry != null) {
                                // The request is to get properties of the "jcr:content" child node ...
                                // Do NOT use "nt:resource", since it extends "mix:referenceable". The JCR spec
                                // does not require that "jcr:content" is of type "nt:resource", but rather just
                                // suggests it. Therefore, we can use "dna:resource", which is identical to
                                // "nt:resource" except it does not extend "mix:referenceable"
                                addProperty(properties, factory, JcrLexicon.PRIMARY_TYPE, DnaLexicon.RESOURCE);
                                addProperty(properties, factory, JcrLexicon.LAST_MODIFIED, dateFactory.create(entry.getDate()));
                            }

                            ByteArrayOutputStream os = new ByteArrayOutputStream();
                            SVNProperties fileProperties = new SVNProperties();
                            getData(contentPath, fileProperties, os);
                            String mimeType = fileProperties.getStringValue(SVNProperty.MIME_TYPE);
                            if (mimeType == null) mimeType = DEFAULT_MIME_TYPE;
                            addProperty(properties, factory, JcrLexicon.MIMETYPE, mimeType);

                            if (os.toByteArray().length > 0) {
                                // Now put the file's content into the "jcr:data" property ...
                                BinaryFactory binaryFactory = getExecutionContext().getValueFactories().getBinaryFactory();
                                addProperty(properties, factory, JcrLexicon.DATA, binaryFactory.create(os.toByteArray()));
                            }
                        }
                    } else {
                        // Determine the corresponding file path for this object ...
                        String filePath = getPathAsString(requestedPath);
                        if (!accessData.getRepositoryRootUrl().equals(workspaceName)) {
                            filePath = filePath.substring(1);
                        }
                        if (children != null) {
                            // Not a "jcr:content" child node but rather an nt:file node, so add the child ...
                            Path contentPath = pathFactory().create(requestedPath, JcrLexicon.CONTENT);
                            children.add(Location.create(contentPath));
                        }
                        if (properties != null) {
                            // Now add the properties to "nt:file" ...
                            addProperty(properties, factory, JcrLexicon.PRIMARY_TYPE, JcrNtLexicon.FILE);
                            ByteArrayOutputStream os = new ByteArrayOutputStream();
                            SVNProperties fileProperties = new SVNProperties();
                            getData(filePath, fileProperties, os);
                            String created = fileProperties.getStringValue(SVNProperty.COMMITTED_DATE);
                            addProperty(properties, factory, JcrLexicon.CREATED, dateFactory.create(created));
                        }
                    }
                }
            } catch (SVNException e) {
                request.setError(e);
            }
        }
        return true;
    }

    /**
     * {@inheritDoc}
     *
     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.ReadNodeRequest)
     */
    @Override
    public void process( ReadNodeRequest request ) {
        logger.trace(request.toString());
        List<Location> children = new LinkedList<Location>();
        List<Property> properties = new LinkedList<Property>();
        if (readNode(request.inWorkspace(), request.at(), properties, children, request)) {
            request.addChildren(children);
            request.addProperties(properties);
            request.setActualLocationOfNode(request.at());
            setCacheableInfo(request);
        }
    }

    /**
     * {@inheritDoc}
     *
     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.ReadAllChildrenRequest)
     */
    @Override
    public void process( ReadAllChildrenRequest request ) {
        logger.trace(request.toString());
        List<Location> children = new LinkedList<Location>();
        if (readNode(request.inWorkspace(), request.of(), null, children, request)) {
            request.addChildren(children);
            request.setActualLocationOfNode(request.of());
            setCacheableInfo(request);
        }

    }

    /**
     * {@inheritDoc}
     *
     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.ReadAllPropertiesRequest)
     */
    @Override
    public void process( ReadAllPropertiesRequest request ) {
        logger.trace(request.toString());
        List<Property> properties = new LinkedList<Property>();
        if (readNode(request.inWorkspace(), request.at(), properties, null, request)) {
            request.addProperties(properties);
            request.setActualLocationOfNode(request.at());
            setCacheableInfo(request);
        }
    }

    /**
     * {@inheritDoc}
     *
     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.CreateNodeRequest)
     */
    @Override
    public void process( CreateNodeRequest request ) {
        updatesAllowed(request);
    }

    /**
     * {@inheritDoc}
     *
     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.UpdatePropertiesRequest)
     */
    @Override
    public void process( UpdatePropertiesRequest request ) {
        logger.trace(request.toString());
        verifyUpdatesAllowed();
    }

    /**
     * {@inheritDoc}
     *
     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.CopyBranchRequest)
     */
    @Override
    public void process( CopyBranchRequest request ) {
        updatesAllowed(request);
    }

    /**
     * {@inheritDoc}
     *
     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.CloneBranchRequest)
     */
    @Override
    public void process( CloneBranchRequest request ) {
        updatesAllowed(request);
    }

    /**
     * {@inheritDoc}
     *
     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.DeleteBranchRequest)
     */
    @Override
    public void process( DeleteBranchRequest request ) {
        updatesAllowed(request);
    }

    /**
     * {@inheritDoc}
     *
     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.MoveBranchRequest)
     */
    @Override
    public void process( MoveBranchRequest request ) {
        updatesAllowed(request);
    }

    /**
     * {@inheritDoc}
     *
     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.RenameNodeRequest)
     */
    @Override
    public void process( RenameNodeRequest request ) {
        if (updatesAllowed(request)) super.process(request);
    }

    /**
     * {@inheritDoc}
     *
     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.VerifyWorkspaceRequest)
     */
    @Override
    public void process( VerifyWorkspaceRequest request ) {
        // If the request contains a null name, then we use the default ...
        String workspaceName = request.workspaceName();
        if (workspaceName == null) workspaceName = defaultWorkspace.getLocation().toDecodedString();

        SVNRepository repository = null;
        if (!this.creatingWorkspacesAllowed) {
            // Then the workspace name must be one of the available names ...
            boolean found = false;
            for (String available : this.availableWorkspaceNames) {
                if (workspaceName.equals(available)) {
                    found = true;
                    break;
                }
                repository = SVNRepositoryUtil.createRepository(available, accessData.getUsername(), accessData.getPassword());
                // check if the workspace is conform
                if (SVNRepositoryUtil.isDirectory(repository, "")
                    && repository.getLocation().toDecodedString().equals(workspaceName)) {
                    found = true;
                    break;
                }
            }
            if (!found) {
                request.setError(new InvalidWorkspaceException(
                                                               SVNRepositoryConnectorI18n.workspaceDoesNotExist.text(workspaceName)));
                return;
            }
        }

        // Verify that there is a repos at the path given by the workspace name ...
        repository = SVNRepositoryUtil.createRepository(workspaceName, accessData.getUsername(), accessData.getPassword());
        if (SVNRepositoryUtil.isDirectory(repository, "")) {
            request.setActualWorkspaceName(repository.getLocation().toDecodedString());
            request.setActualRootLocation(Location.create(pathFactory().createRootPath()));
        } else {
            request.setError(new InvalidWorkspaceException(SVNRepositoryConnectorI18n.workspaceDoesNotExist.text(workspaceName)));
        }
    }

    /**
     * {@inheritDoc}
     *
     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.GetWorkspacesRequest)
     */
    @Override
    public void process( GetWorkspacesRequest request ) {
        // Return the set of available workspace names, even if new workspaces can be created ...
        Set<String> names = new HashSet<String>();
        for (String name : this.availableWorkspaceNames) {
            SVNRepository repos = SVNRepositoryUtil.createRepository(name, accessData.getUsername(), accessData.getPassword());
            if (repos != null && SVNRepositoryUtil.isDirectory(repos, "")) {
                names.add(repos.getLocation().toDecodedString());
            } else {
                request.setError(new InvalidWorkspaceException(SVNRepositoryConnectorI18n.workspaceDoesNotExist.text(name)));
            }
        }
        request.setAvailableWorkspaceNames(Collections.unmodifiableSet(names));
    }

    /**
     * {@inheritDoc}
     *
     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.CloneWorkspaceRequest)
     */
    @Override
    public void process( CloneWorkspaceRequest request ) {
        if (!updatesAllowed) {
            request.setError(new InvalidRequestException(
                                                         SVNRepositoryConnectorI18n.sourceDoesNotSupportCloningWorkspaces.text(getSourceName())));
        }
    }

    /**
     * {@inheritDoc}
     *
     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.CreateWorkspaceRequest)
     */
    @Override
    public void process( CreateWorkspaceRequest request ) {
        final String workspaceName = request.desiredNameOfNewWorkspace();
        if (!creatingWorkspacesAllowed) {
            String msg = SVNRepositoryConnectorI18n.unableToCreateWorkspaces.text(getSourceName(), workspaceName);
            request.setError(new InvalidRequestException(msg));
            return;
        }
        // This doesn't create the directory representing the workspace (it must already exist), but it will add
        // the workspace name to the available names ...
        SVNRepository repository = SVNRepositoryUtil.createRepository(workspaceName,
                                                                      accessData.getUsername(),
                                                                      accessData.getPassword());
        if (SVNRepositoryUtil.isDirectory(repository, "")) {
            request.setActualWorkspaceName(repository.getLocation().toDecodedString());
            request.setActualRootLocation(Location.create(pathFactory().createRootPath()));
            availableWorkspaceNames.add(repository.getLocation().toDecodedString());
        } else {
            request.setError(new InvalidWorkspaceException(SVNRepositoryConnectorI18n.workspaceDoesNotExist.text(workspaceName)));
        }

    }

    /**
     * {@inheritDoc}
     *
     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.DestroyWorkspaceRequest)
     */
    @Override
    public void process( DestroyWorkspaceRequest request ) {
        final String workspaceName = request.workspaceName();
        if (!creatingWorkspacesAllowed) {
            String msg = SVNRepositoryConnectorI18n.unableToCreateWorkspaces.text(getSourceName(), workspaceName);
            request.setError(new InvalidRequestException(msg));
        }
        // This doesn't delete the file/directory; rather, it just remove the workspace from the available set ...
        if (!this.availableWorkspaceNames.remove(workspaceName)) {
            request.setError(new InvalidWorkspaceException(SVNRepositoryConnectorI18n.workspaceDoesNotExist.text(workspaceName)));
        }
    }

    /**
     * Verify if change is allowed on a specific source.
     *
     * @throws RepositorySourceException if change on that repository source is not allowed.
     */
    protected void verifyUpdatesAllowed() {
        if (!updatesAllowed) {
            throw new InvalidRequestException(SVNRepositoryConnectorI18n.sourceIsReadOnly.text(getSourceName()));
        }
    }

    protected boolean updatesAllowed( Request request ) {
        if (!updatesAllowed) {
            request.setError(new InvalidRequestException(SVNRepositoryConnectorI18n.sourceIsReadOnly.text(getSourceName())));
        }
        return !request.hasError();
    }

    /**
     * Factory for sample name.
     *
     * @return the name factory
     */
    protected NameFactory nameFactory() {
        return getExecutionContext().getValueFactories().getNameFactory();
    }

    /**
     * Factory for path creation.
     *
     * @return a path factory.
     */
    protected PathFactory pathFactory() {
        return getExecutionContext().getValueFactories().getPathFactory();
    }

    /**
     * Factory for property creation.
     *
     * @return the property factory.
     */
    protected PropertyFactory propertyFactory() {
        return getExecutionContext().getPropertyFactory();
    }

    /**
     * Factory for date creation.
     *
     * @return the date factory.
     */
    protected DateTimeFactory dateFactory() {
        return getExecutionContext().getValueFactories().getDateFactory();
    }

    /**
     * Factory for binary creation.
     *
     * @return the binary factory..
     */
    protected ValueFactory<Binary> binaryFactory() {
        return getExecutionContext().getValueFactories().getBinaryFactory();
    }

    /**
     * Get the path for a locarion and check if the path is null or not.
     *
     * @param location - the location.
     * @param request - the requested path.
     * @return the path.
     * @throws RepositorySourceException if the path of a location is null.
     */
    protected Path getPathFor( Location location,
                               Request request ) {
        Path path = location.getPath();
        if (path == null) {
            I18n msg = SVNRepositoryConnectorI18n.locationInRequestMustHavePath;
            throw new RepositorySourceException(getSourceName(), msg.text(getSourceName(), request));
        }
        return path;
    }

    /**
     * Get the content of a file.
     *
     * @param path - the path to that file.
     * @param properties - the properties of the file.
     * @param os - the output stream where to store the content.
     * @throws SVNException - throws if such path is not at that revision or in case of a connection problem.
     */
    protected void getData( String path,
                            SVNProperties properties,
                            OutputStream os ) throws SVNException {
        getDefaultWorkspace().getFile(path, -1, properties, os);

    }

    /**
     * Get the repository driver.
     *
     * @return repository
     */
    public SVNRepository getDefaultWorkspace() {
        return defaultWorkspace;
    }

    /**
     * Validate the kind of node and throws an exception if necessary.
     *
     * @param repos
     * @param requestedPath
     * @return the kind.
     */
    protected SVNNodeKind validateNodeKind( SVNRepository repos,
                                            Path requestedPath ) {
        SVNNodeKind kind;
        String myPath;
        if (getPathAsString(requestedPath).trim().equals("/")) {
            myPath = getPathAsString(requestedPath);
        } else if (requestedPath.endsWith(JcrLexicon.CONTENT)) {
            myPath = getPathAsString(requestedPath.getParent());
        } else {
            // directory and file
            myPath = getPathAsString(requestedPath);
        }

        try {

            kind = repos.checkPath(myPath, -1);
            if (kind == SVNNodeKind.NONE) {
                // node does not exist or requested node is not correct.
                throw new PathNotFoundException(Location.create(requestedPath), null,
                                                SVNRepositoryConnectorI18n.nodeDoesNotExist.text(myPath));
            } else if (kind == SVNNodeKind.UNKNOWN) {
                // node is unknown
                throw new PathNotFoundException(Location.create(requestedPath), null,
                                                SVNRepositoryConnectorI18n.nodeIsActuallyUnknow.text(myPath));
            }
        } catch (SVNException e) {
            throw new RepositorySourceException(
                                                getSourceName(),
                                                SVNRepositoryConnectorI18n.connectingFailureOrUserAuthenticationProblem.text(getSourceName()));
        }

        return kind;
    }

    private String getPathAsString( Path path ) {
        return path.getString(getExecutionContext().getNamespaceRegistry());
    }

    /**
     * Get some important informations of a path
     *
     * @param repos
     * @param path - the path
     * @return - the {@link SVNDirEntry}, or null if there is no such entry
     */
    protected SVNDirEntry getEntryInfo( SVNRepository repos,
                                        String path ) {
        assert path != null;
        SVNDirEntry entry = null;
        try {
            entry = repos.info(path, -1);
        } catch (SVNException e) {
            throw new RepositorySourceException(
                                                getSourceName(),
                                                SVNRepositoryConnectorI18n.connectingFailureOrUserAuthenticationProblem.text(getSourceName()));
        }
        return entry;
    }

    /**
     * Open the directories where change has to be made.
     *
     * @param editor - abstract editor.
     * @param rootPath - the pa to open.
     * @throws SVNException when a error occur.
     */
    protected static void openDirectories( ISVNEditor editor,
                                           String rootPath ) throws SVNException {
        assert rootPath != null;
        int pos = rootPath.indexOf('/', 0);
        while (pos != -1) {
            String dir = rootPath.substring(0, pos);
            editor.openDir(dir, -1);
            pos = rootPath.indexOf('/', pos + 1);
        }
        String dir = rootPath.substring(0, rootPath.length());
        editor.openDir(dir, -1);
    }

    /**
     * Close the directories where change was made.
     *
     * @param editor - the abstract editor.
     * @param path - the directories to open.
     * @throws SVNException when a error occur.
     */
    protected static void closeDirectories( ISVNEditor editor,
                                            String path ) throws SVNException {
        int length = path.length() - 1;
        int pos = path.lastIndexOf('/', length);
        editor.closeDir();
        while (pos != -1) {
            editor.closeDir();
            pos = path.lastIndexOf('/', pos - 1);
        }
    }

    /**
     * Get the last revision.
     *
     * @param repos
     * @return the last revision number.
     * @throws Exception
     */
    public long getLatestRevision( SVNRepository repos ) throws Exception {
        try {
            return repos.getLatestRevision();
        } catch (SVNException e) {
            e.printStackTrace();
            // logger.error( "svn error: " );
            throw e;
        }
    }

    /**
     * Add directory in a repository
     *
     * @param repository - the repository.
     * @param root - the root path has to exist.
     * @param child - new path to be added.
     * @param message - information about the change action.
     * @throws SVNException when a error occur.
     */
    protected void addDirEntry( SVNRepository repository,
                                String root,
                                String child,
                                String message ) throws SVNException {
        assert root.trim().length() != 0;
        SVNNodeKind rootKind = repository.checkPath(root, -1);
        if (rootKind == SVNNodeKind.UNKNOWN) {
            SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.UNKNOWN,
                                                         "path with name '{0}' is unknown in the repository",
                                                         root);
            throw new SVNException(err);
        } else if (rootKind == SVNNodeKind.NONE) {
            SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.UNKNOWN,
                                                         "path with name '{0}' is missing in the repository",
                                                         root);
            throw new SVNException(err);
        } else if (rootKind == SVNNodeKind.FILE) {
            SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.UNKNOWN,
                                                         "path with name '{0}' is a file, you need a directory",
                                                         root);
            throw new SVNException(err);
        } else if (rootKind == SVNNodeKind.DIR) {
            ISVNEditor editor = repository.getCommitEditor(message, null, true, null);
            if (root.length() == 1 && root.charAt(0) == '/') {
                addProcess(repository, editor, root, "", child);
            } else {
                String rootPath = root.substring(1);
                addProcess(repository, editor, rootPath, null, child);
            }
        }
    }

    private void addProcess( SVNRepository repos,
                             ISVNEditor editor,
                             String rootPath,
                             String editedRoot,
                             String childSegmentName ) throws SVNException {
        openDirectories(editor, editedRoot);
        // test if so a directory does not exist.
        SVNNodeKind childKind = repos.checkPath(childSegmentName, -1);
        if (childKind == SVNNodeKind.NONE) {
            editor.addDir(childSegmentName, null, -1);
            closeDirectories(editor, childSegmentName);
            if (editedRoot != null) {
                closeDirectories(editor, editedRoot);
            } else {
                closeDirectories(editor, rootPath);
            }

        } else {
            closeDirectories(editor, childSegmentName);
            if (editedRoot != null) {
                closeDirectories(editor, editedRoot);
            } else {
                closeDirectories(editor, rootPath);
            }
        }
    }

    /**
     * Create a directory .
     *
     * @param repos
     * @param root - the root directory where the created directory will reside
     * @param childName - the name of the created directory.
     * @param message - comment for the creation.
     * @throws SVNException - if during the creation, there is an error.
     */
    @SuppressWarnings( "unused" )
    private void mkdir( SVNRepository repos,
                        String root,
                        String childName,
                        String message ) throws SVNException {
        SVNNodeKind childKind = repos.checkPath(childName, -1);
        if (childKind == SVNNodeKind.NONE) {
            ScmAction addNodeAction = addDirectory(root, childName);
            SVNActionExecutor executor = new SVNActionExecutor(repos);
            executor.execute(addNodeAction, message);
        } else {
            SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.UNKNOWN, "Item with name '{0}' can't be created", childName);
            throw new SVNException(err);
        }
    }

    /**
     * Create a file.
     *
     * @param path
     * @param file
     * @param content
     * @param message
     * @throws SVNException
     */
    @SuppressWarnings( "unused" )
    private void newFile( String path,
                          String file,
                          byte[] content,
                          String message ) throws SVNException {
        SVNNodeKind childKind = defaultWorkspace.checkPath(file, -1);
        if (childKind == SVNNodeKind.NONE) {
            ScmAction addFileNodeAction = addFile(path, file, content);
            SVNActionExecutor executor = new SVNActionExecutor(defaultWorkspace);
            executor.execute(addFileNodeAction, message);
        } else {
            SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.UNKNOWN,
                                                         "Item with name '{0}' can't be created (already exist)",
                                                         file);
            throw new SVNException(err);
        }
    }

    /**
     * {@inheritDoc}
     *
     * @see org.jboss.dna.connector.scm.ScmActionFactory#addDirectory(java.lang.String, java.lang.String)
     */
    public ScmAction addDirectory( String root,
                                   String path ) {
        return new AddDirectory(root, path);
    }

    /**
     * {@inheritDoc}
     *
     * @see org.jboss.dna.connector.scm.ScmActionFactory#addFile(java.lang.String, java.lang.String, byte[])
     */
    public ScmAction addFile( String path,
                              String file,
                              byte[] content ) {
        return new AddFile(path, file, content);
    }

    /**
     * {@inheritDoc}
     *
     * @see org.jboss.dna.connector.scm.ScmActionFactory#copyDirectory(java.lang.String, java.lang.String, long)
     */
    public ScmAction copyDirectory( String path,
                                    String newPath,
                                    long revision ) {
        return null;
    }

    /**
     * {@inheritDoc}
     *
     * @see org.jboss.dna.connector.scm.ScmActionFactory#deleteDirectory(java.lang.String)
     */
    public ScmAction deleteDirectory( String path ) {
        return null;
    }

    /**
     * {@inheritDoc}
     *
     * @see org.jboss.dna.connector.scm.ScmActionFactory#deleteFile(java.lang.String, java.lang.String)
     */
    public ScmAction deleteFile( String path,
                                 String file ) {
        return null;
    }

    /**
     * root should be the last, previously created, parent folder. Each directory in the path will be created.
     */
    public static class AddDirectory implements ScmAction {
        private String root;
        private String path;

        public AddDirectory( String root,
                             String path ) {
            this.root = root;
            this.path = path;
        }

        public void applyAction( Object context ) throws SVNException {

            ISVNEditor editor = (ISVNEditor)context;

            openDirectories(editor, this.root);
            String[] paths = this.path.split("/");
            String newPath = this.root;
            for (int i = 0, length = paths.length; i < length; i++) {
                newPath = (newPath.length() != 0) ? newPath + "/" + paths[i] : paths[i];

                editor.addDir(newPath, null, -1);
            }

            closeDirectories(editor, path);
            closeDirectories(editor, this.root);
        }
    }

    public static class AddFile implements ScmAction {
        private String path;
        private String file;
        private byte[] content;

        public AddFile( String path,
                        String file,
                        byte[] content ) {
            this.path = path;
            this.file = file;
            this.content = content;
        }

        public void applyAction( Object context ) throws Exception {
            ISVNEditor editor = (ISVNEditor)context;
            openDirectories(editor, path);

            editor.addFile(path + "/" + file, null, -1);
            editor.applyTextDelta(path + "/" + file, null);
            SVNDeltaGenerator deltaGenerator = new SVNDeltaGenerator();
            String checksum = deltaGenerator.sendDelta(path + "/" + file, new ByteArrayInputStream(this.content), editor, true);
            editor.closeFile(path + "/" + file, checksum);

            closeDirectories(editor, path);

        }

    }

    @SuppressWarnings( "unused" )
    private byte[] getContent( Object[] objs ) {
        byte[] content = null;
        for (Object object : objs) {
            if (object != null && object instanceof Binary) {
                Binary buf = (Binary)object;
                content = buf.getBytes();
            }
        }
        return content;
    }

    @SuppressWarnings( "unused" )
    private Object[] values( Collection<Property> childNodeProperties ) {
        Set<Object> result = new HashSet<Object>();
        for (Property property : childNodeProperties) {
            result.add(property.getFirstValue());
        }
        return result.toArray();
    }

    private void checkThePath( Path path,
                               Request request ) {
        for (Path.Segment segment : path) {
            // Verify the segment is valid ...
            if (segment.getIndex() > 1) {
                I18n msg = SVNRepositoryConnectorI18n.sameNameSiblingsAreNotAllowed;
                throw new RepositorySourceException(getSourceName(), msg.text(getSourceName(), request));
            }
            // TODO
            // if (!segment.getName().getNamespaceUri().equals(defaultNamespaceUri)) {
            // I18n msg = SVNRepositoryConnectorI18n.onlyTheDefaultNamespaceIsAllowed;
            // throw new RepositorySourceException(getSourceName(), msg.text(getSourceName(), request));
            // }
        }
    }

    protected SVNRepository getWorkspaceDirectory( String workspaceName ) {
        SVNRepository repository = defaultWorkspace;
        if (workspaceName != null) {
            SVNRepository repos = SVNRepositoryUtil.createRepository(workspaceName,
                                                                     accessData.getUsername(),
                                                                     accessData.getPassword());
            if (SVNRepositoryUtil.isDirectory(repos, "")) {
                repository = repos;
            } else {
                return null;
            }
        }
        return repository;
    }

    protected SVNNodeKind getNodeKind( SVNRepository repository,
                                       Path path,
                                       String repositoryRootUrl,
                                       String inWorkspace ) throws SVNException {
        assert path != null;
        assert repositoryRootUrl != null;
        assert inWorkspace != null;
        // See if the path is a "jcr:content" node ...
        if (path.endsWith(JcrLexicon.CONTENT)) {
            // We only want to use the parent path to find the actual file ...
            path = path.getParent();
        }
        String pathAsString = getPathAsString(path);
        if (!repositoryRootUrl.equals(inWorkspace)) {
            pathAsString = pathAsString.substring(1);
        }
        SVNNodeKind kind = repository.checkPath(pathAsString, -1);
        if (kind == SVNNodeKind.NONE) {
            // node does not exist or requested node is not correct.
            throw new PathNotFoundException(Location.create(path), null,
                                            SVNRepositoryConnectorI18n.nodeDoesNotExist.text(pathAsString));
        } else if (kind == SVNNodeKind.UNKNOWN) {
            // node is unknown
            throw new PathNotFoundException(Location.create(path), null,
                                            SVNRepositoryConnectorI18n.nodeIsActuallyUnknow.text(pathAsString));
        }
        return kind;
    }
}
TOP

Related Classes of org.jboss.dna.connector.svn.SVNRepositoryRequestProcessor$AddFile

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.