Package org.wso2.carbon.registry.synchronization.operation

Source Code of org.wso2.carbon.registry.synchronization.operation.CheckInCommand

/*
* Copyright (c) 2008, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* Licensed 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.wso2.carbon.registry.synchronization.operation;

import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMText;
import org.apache.axiom.om.util.Base64;
import org.wso2.carbon.registry.core.Registry;
import org.wso2.carbon.registry.core.exceptions.RegistryException;
import org.wso2.carbon.registry.core.utils.RegistryUtils;
import org.wso2.carbon.registry.synchronization.SynchronizationConstants;
import org.wso2.carbon.registry.synchronization.SynchronizationException;
import org.wso2.carbon.registry.synchronization.UserInputCallback;
import org.wso2.carbon.registry.synchronization.Utils;
import org.wso2.carbon.registry.synchronization.message.MessageCode;

import javax.xml.namespace.QName;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import java.io.*;
import java.util.LinkedList;
import java.util.List;
import java.util.zip.ZipInputStream;

/**
* This command is used to perform a check-in operation which will upload the files and directories
* from the local filesystem into the provided registry instance.
*/
@SuppressWarnings({"ResultOfMethodCallIgnored", "unused"})
public class CheckInCommand {

    private String inputFile = null;
    private String workingDir = null;
    private String registryUrl = null;
    private String checkInPath = null;
    private String userUrl = null;
    private String username = null;
    private boolean ignoreConflicts = true;
    private boolean cleanRegistry = false;
    private List<String> filesToClean = new LinkedList<String>();
    private boolean testContentChanged = true;

    /**
     * Creates an instance of a check-in command which can be executed against a provided registry
     * instance.
     *
     * @param inputFile          if the content is to be uploaded from a single meta file, this
     *                           parameter can be used to specify the path to the meta file.
     * @param workingDir         if the content is to be uploaded from a directory on the
     *                           filesystem, this parameter can be used to specify the path to the
     *                           corresponding location.
     * @param userUrl            aggregate URL containing a concatenation of the registry URL and
     *                           the resource path that is capable of referencing a remote resource.
     *                           This url will contain only the resource path if the resource was
     *                           local to the given registry instance.
     * @param username           the name of the user (which should be a valid username on the
     *                           target server on which the provided registry instance is running)
     *                           that performs this operation.
     * @param ignoreConflicts    ignore conflicts in the server side
     * @param cleanRegistry      whether the embedded registry instance must be cleaned after the
     *                           execution of the operation.
     * @param testContentChanged when this parameter is set to true, check-in will only happen if
     *                           the content has changed.
     *
     * @throws SynchronizationException if the operation failed.
     */
    public CheckInCommand(String inputFile,
                          String workingDir,
                          String userUrl,
                          String username,
                          boolean ignoreConflicts,
                          boolean cleanRegistry,
                          boolean testContentChanged) throws SynchronizationException {
        // now if the user url is different to the registry url we are going to consider that as
        // well.

        this.inputFile = inputFile;
        this.workingDir = workingDir;
        this.userUrl = userUrl;
        this.username = username;
        this.ignoreConflicts = ignoreConflicts;
        this.cleanRegistry = cleanRegistry;
        this.testContentChanged = testContentChanged;

        // get the update details form the meta element of the current checkout
        OMElement metaOMElement = Utils.getMetaOMElement(workingDir);
        if (metaOMElement != null) {
            checkInPath = metaOMElement.getAttributeValue(new QName("path"));
        }

        if (userUrl != null) {
            registryUrl = Utils.getRegistryUrl(userUrl);
            String suggestedCheckInPath = Utils.getPath(userUrl);
            if (suggestedCheckInPath == null || suggestedCheckInPath.equals("")) {
                suggestedCheckInPath = "/";
                // we are converting the root path to the current directory of the file system
            }
            if (!suggestedCheckInPath.equals(checkInPath)) {
                this.testContentChanged = false;
                checkInPath = suggestedCheckInPath;
            }
        } else {
            if (metaOMElement == null) {
                throw new SynchronizationException(MessageCode.CHECKOUT_BEFORE_CHECK_IN);
            }
            registryUrl = metaOMElement.getAttributeValue(new QName("registryUrl"));
        }
    }

    /**
     * This method will execute the check-in command utilizing the various parameters passed when
     * creating the instance of the command. This method accepts the users preference if a deletion
     * of a file or directory is required in the process.
     *
     * @param registry the registry instance to be used.
     * @param callback the instance of a callback that can be used to determine the user's
     *                 preference before deleting an existing file or directory during the update
     *                 after the check-in has been done. If this parameter is null, the default
     *                 behaviour of deleting the existing file will be used.
     *
     * @throws SynchronizationException if the operation failed.
     */
    public void execute(Registry registry, UserInputCallback callback)
            throws SynchronizationException {
        if (inputFile != null) {
            // restore a single file.
            restoreFromFile(registry);
        } else {
            // restore from a file system only if the content did not change.
            if (!testContentChanged || (workingDir != null
                    && Utils.contentChanged(new File(workingDir)))) {
                restoreFromFileSystem(registry, callback);
            }
        }
    }

    /**
     * This method will execute the check-in command utilizing the various parameters passed when
     * creating the instance of the command.
     *
     * @param registry the registry instance to be used.
     *
     * @throws SynchronizationException if the operation failed.
     */
    public void execute(Registry registry) throws SynchronizationException {
        execute(registry, null);
    }

    // Restores the given resources and collections from a dump file.
    private void restoreFromFile(Registry registry) throws SynchronizationException {
        String workingDir = this.workingDir;

        if (workingDir != null) {
            inputFile = workingDir + File.separator + inputFile;
        }

        // do the restoring
        try {
            ZipInputStream zis = new ZipInputStream(new FileInputStream(inputFile));
            zis.getNextEntry();
            Reader reader = new InputStreamReader(zis);
            registry.restore(checkInPath, reader);
        } catch (FileNotFoundException e) {
            throw new SynchronizationException(MessageCode.FILE_DOES_NOT_EXIST, e,
                    new String[]{"Output file" + inputFile});
        } catch (Exception e) {
            throw new SynchronizationException(MessageCode.ERROR_IN_RESTORING, e,
                    new String[]{"path: " + checkInPath,
                            "registry url: " + registryUrl,
                            "username: " + username});
        }

        if (cleanRegistry && registryUrl == null) {
            Utils.cleanEmbeddedRegistry();
        }
    }

    // Restores the given resources and collections from files and folders on the filesystem.
    private void restoreFromFileSystem(Registry registry, UserInputCallback callback)
            throws SynchronizationException {
        // we are doing the check-in through a temp file. (so assumed enough spaces are there)
        File tempFile = null;
        boolean deleteTempFileFailed = false;
        XMLStreamWriter xmlWriter = null;
        Writer writer = null;
        try {
            try {
                tempFile = File.createTempFile(SynchronizationConstants.DUMP_META_FILE_NAME,
                        SynchronizationConstants.META_FILE_EXTENSION);

                try {
                    writer = new FileWriter(tempFile);
                    // wrap the writer with an xml stream writer
                    xmlWriter = XMLOutputFactory.newInstance().createXMLStreamWriter(writer);
                    // prepare the dump xml
                    xmlWriter.writeStartDocument();
                    createMetaElement(xmlWriter, workingDir, checkInPath);
                    xmlWriter.writeEndDocument();
                } finally {
                    try {
                        if (xmlWriter != null) {
                            xmlWriter.close();
                        }
                    } finally {
                        if (writer != null) {
                            writer.close();
                        }
                    }
                }
            } catch (IOException e) {
                throw new SynchronizationException(
                        MessageCode.ERROR_IN_CREATING_TEMP_FILE_FOR_DUMP,
                        e);
            } catch (XMLStreamException e) {
                throw new SynchronizationException(
                        MessageCode.ERROR_IN_CREATING_XML_STREAM_WRITER, e);
            }

            // do the restoring
            try {
                Reader reader = null;
                try {
                    reader = new FileReader(tempFile);
                    registry.restore(checkInPath, reader);
                } finally {
                    if (reader != null) {
                        reader.close();
                    }
                }
            } catch (IOException e) {
                throw new SynchronizationException(
                        MessageCode.ERROR_IN_READING_TEMP_FILE_OF_DUMP, e);
            } catch (RegistryException e) {
                throw new SynchronizationException(MessageCode.ERROR_IN_RESTORING, e,
                        new String[]{"path: " + checkInPath,
                                "registry url: " + registryUrl,
                                "username: " + username});
            }
        } finally {
            if (tempFile != null) {
                // Our intention here is to delete the temporary file. We are not bothered whether
                // this operation fails.
                deleteTempFileFailed = !tempFile.delete();
            }
        }
        if (deleteTempFileFailed) {
            throw new SynchronizationException(MessageCode.ERROR_IN_CLEANING_UP,
                    new String[]{"file path: " + tempFile.getAbsolutePath()});
        }

        if (cleanRegistry && registryUrl == null) {
            Utils.cleanEmbeddedRegistry();
        }

        // clean all the dangling meta files.
        if (filesToClean != null && filesToClean.size() > 0) {
            for (String filePath : filesToClean) {
                if (!Utils.deleteFile(new File(filePath))) {
                    throw new SynchronizationException(MessageCode.ERROR_IN_CLEANING_UP,
                            new String[]{"file path: " + filePath});
                }
            }
        }

        // at the end we are doing an update too
        UpdateCommand updateCommand =
                new UpdateCommand(inputFile, workingDir, userUrl, true, username, cleanRegistry);
        updateCommand.execute(registry, callback);
        updateCommand.setSilentUpdate(false);
    }

    // Creates the dump element from the given file or directory.
    private void createMetaElement(XMLStreamWriter xmlWriter, String filePath, String path)
            throws SynchronizationException, XMLStreamException {
        File file = new File(filePath);
        if (file.isDirectory()) {
            createDirectoryMetaElement(xmlWriter, filePath, path);
        } else {
            createMetaElementForChild(xmlWriter, filePath, path, null);
        }
    }

    // Creates the dump element from the given directory. If the path is not given it is retrieved
    // from the meta file.
    private void createDirectoryMetaElement(XMLStreamWriter xmlWriter, String filePath, String path)
            throws SynchronizationException, XMLStreamException {
        // first get the meta file of the directory.
        String metaDirectoryPath = filePath + File.separator +
                SynchronizationConstants.META_DIRECTORY;
        String metaFilePath = metaDirectoryPath + File.separator +
                SynchronizationConstants.META_FILE_PREFIX +
                SynchronizationConstants.META_FILE_EXTENSION;

        // confirm the existence of the meta file.
        OMElement metaElement = Utils.getOMElementFromMetaFile(metaFilePath);
        if (metaElement == null) {
            // will update the meta file in the file system asap it is generated.
            metaElement = Utils.createDefaultMetaFile(true, path, username);
            Utils.createMetaFile(metaFilePath, metaElement);
        }

        // alerting non-backward compatibility...
        String checkoutPathAttribute = metaElement.getAttributeValue(new QName("checkoutPath"));
        if (checkoutPathAttribute != null) {
            throw new SynchronizationException(MessageCode.CHECKOUT_OLD_VERSION);
        }

        // we are re-adjusting the name of the resource to make sure the file name and the resource
        // name is equal
        String resourceName = RegistryUtils.getResourceName(path);
        metaElement.addAttribute("name", resourceName, null);

        // now write the meta data of the meta element to the writer (except children)
        Utils.writeMetaElement(xmlWriter, metaElement);

        // now add the child element to the meta element
        xmlWriter.writeStartElement("children");

        File directory = new File(filePath);
        String[] childrenNames = directory.list();
        List<String> filesToPreserve = new LinkedList<String>();
        if (childrenNames != null) {
            for (String childFileName : childrenNames) {
                // Get childFileName of file or directory
                String childResourceName = Utils.decodeFilename(childFileName);

                if (childResourceName.equals(SynchronizationConstants.META_DIRECTORY)) {
                    continue;
                }
                if (childResourceName.endsWith(SynchronizationConstants.MINE_FILE_POSTFIX) ||
                        childResourceName.endsWith(SynchronizationConstants.SERVER_FILE_POSTFIX)) {
                    // there is an conflicts
                    throw new SynchronizationException(MessageCode.RESOLVE_CONFLICTS);
                }

                String childPath;
                String childFilePath;
                if (path.equals("/")) {
                    childPath = "/" + childResourceName;
                } else {
                    childPath = path + "/" + childResourceName;
                }
                childFilePath = filePath + File.separator + childFileName;
                createMetaElementForChild(xmlWriter, childFilePath, childPath, filesToPreserve);
            }
            filesToPreserve.add(getAbsoluteFilePath(metaFilePath));
            filesToClean.addAll(
                    Utils.cleanUpDirectory(new File(metaDirectoryPath), filesToPreserve));
        }
        xmlWriter.writeEndElement(); // to end children tag.
        xmlWriter.writeEndElement(); // to end resource tag.
        xmlWriter.flush();
    }

    // Creates the dump element from the given child file or directory. If the path is not given it
    // is retrieved from the meta file.
    private void createMetaElementForChild(XMLStreamWriter xmlWriter,
                                           String filePath,
                                           String path,
                                           List<String> filesToPreserve)
            throws SynchronizationException, XMLStreamException {

        File file = new File(filePath);
        String parentFilePath = file.getParent();
        String filename = file.getName();
        OMElement metaElement;
        if (!file.isDirectory()) {

            String metaFilePath =
                    parentFilePath + File.separator + SynchronizationConstants.META_DIRECTORY +
                            File.separator +
                            SynchronizationConstants.META_FILE_PREFIX + filename +
                            SynchronizationConstants.META_FILE_EXTENSION;
            if (filesToPreserve != null) {
                filesToPreserve.add(getAbsoluteFilePath(metaFilePath));
            }

            // confirm the existence of the meta file.
            metaElement = Utils.getOMElementFromMetaFile(metaFilePath);
            // will update the meta file in the file system asap it is generated.
            if (metaElement == null) {
                metaElement = Utils.createDefaultMetaFile(false, path, username);
                Utils.createMetaFile(metaFilePath, metaElement);
            }

            // we are re-adjusting the name of the resource to make sure the file name and the
            // resource name is equal
            String resourceName = RegistryUtils.getResourceName(path);
            metaElement.addAttribute("name", resourceName, null);
            if (!ignoreConflicts) {
                // we only set the ignoreConflict attribute only if it is failing.
                metaElement.addAttribute("ignoreConflicts", "false", null);
            }

            // now write the meta data of the meta element to the writer (except children)
            Utils.writeMetaElement(xmlWriter, metaElement);

            // adding the content
            byte[] content = Utils.getBytesFromFile(file);
            String encodedContent = Base64.encode(content);

            OMFactory factory = OMAbstractFactory.getOMFactory();

            OMElement contentEle = factory.createOMElement(new QName("content"));
            OMText contentText = factory.createOMText(encodedContent);
            contentEle.addChild(contentText);

            contentEle.serialize(xmlWriter);

            xmlWriter.writeEndElement(); // to end resource tag.
            xmlWriter.flush();
        } else {
            createDirectoryMetaElement(xmlWriter, filePath, path);
        }
    }

    // Gets the absolute path of the given file path.
    private String getAbsoluteFilePath(String filePath) {
        return (new File(filePath)).getAbsolutePath();
    }
}
TOP

Related Classes of org.wso2.carbon.registry.synchronization.operation.CheckInCommand

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.