Package org.wso2.carbon.registry.synchronization

Source Code of org.wso2.carbon.registry.synchronization.Utils

/*
* 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;

import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.wso2.carbon.registry.core.config.RegistryContext;
import org.wso2.carbon.registry.core.utils.LogWriter;
import org.wso2.carbon.registry.core.utils.RegistryUtils;
import org.wso2.carbon.registry.synchronization.message.Message;
import org.wso2.carbon.registry.synchronization.message.MessageCode;

import javax.xml.namespace.QName;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import java.io.*;
import java.math.BigInteger;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

/**
* Some utility methods used by the synchronization operations.
*/
@SuppressWarnings("ResultOfMethodCallIgnored")
public class Utils {

    /**
     * This method writes the meta element to the xml stream up to the children.
     *
     * @param xmlWriter   xml writer
     * @param metaElement meta element to write
     *
     * @throws XMLStreamException if the operation failed
     */
    public static void writeMetaElement(XMLStreamWriter xmlWriter, OMElement metaElement)
            throws XMLStreamException {

        xmlWriter.writeStartElement("resource");

        // adding path as an attribute, updated dump has name instead of path
        String name = metaElement.getAttributeValue(new QName("name"));
        xmlWriter.writeAttribute("name", name);

        // adding ignoreConflicts as an attribute, if it is available.:
        String ignoreConflicts = metaElement.getAttributeValue(new QName("ignoreConflicts"));
        if (ignoreConflicts != null) {
            xmlWriter.writeAttribute("ignoreConflicts", ignoreConflicts);
        }

        // adding isCollection as an attribute
        String isCollectionStr = metaElement.getAttributeValue(new QName("isCollection"));
        xmlWriter.writeAttribute("isCollection", isCollectionStr);

        Iterator childrenIt = metaElement.getChildren();
        while (childrenIt.hasNext()) {
            Object childObj = childrenIt.next();
            if (!(childObj instanceof OMElement)) {
                continue;
            }
            OMElement childElement = (OMElement) childObj;
            String childName = childElement.getLocalName();

            // the following elements will be serialized to the writer directly
            if (childName.equals("mediaType") ||
                    childName.equals("creator") ||
                    childName.equals("createdTime") ||
                    childName.equals("lastUpdater") ||
                    childName.equals("lastModified") ||
                    childName.equals("description") ||
                    childName.equals("properties") ||
                    childName.equals("comments") ||
                    childName.equals("taggings") ||
                    childName.equals("ratings") ||
                    childName.equals("version") ||
                    childName.equals("associations")) {
                childElement.serialize(xmlWriter);
            }
        }
    }

    /**
     * This method reads the xml stream up to the children and return the meta element.
     *
     * @param xmlReader the xml reader.
     *
     * @return the meta element.
     * @throws SynchronizationException if the provided XML is invalid.
     * @throws XMLStreamException       if XML parsing failed.
     */
    public static OMElement readMetaElement(XMLStreamReader xmlReader)
            throws SynchronizationException, XMLStreamException {
        try {
            while (!xmlReader.isStartElement() && xmlReader.hasNext()) {
                xmlReader.next();
            }

            if (!xmlReader.hasNext()) {
                // nothing to parse
                return null;
            }

            if (!xmlReader.getLocalName().equals("resource")) {
                throw new SynchronizationException(
                        MessageCode.INVALID_DUMP_CREATE_META_FILE);

            }

            // alerting non-backward compatibility...
            String pathAttribute = xmlReader.getAttributeValue(null, "path");
            if (pathAttribute != null) {
                throw new SynchronizationException(MessageCode.CHECKOUT_OLD_VERSION);
            }

            OMFactory factory = OMAbstractFactory.getOMFactory();
            OMElement root = factory.createOMElement(new QName("resource"));

            String resourceName = xmlReader.getAttributeValue(null, "name");
            String isCollectionString = xmlReader.getAttributeValue(null, "isCollection");

            root.addAttribute("name", resourceName, null);
            root.addAttribute("isCollection", isCollectionString, null);

            // traversing to the next element
            do {
                xmlReader.next();
            } while (!xmlReader.isStartElement() && xmlReader.hasNext());

            while (xmlReader.hasNext()) {
                String localName = xmlReader.getLocalName();

                // version
                if (localName.equals("version")) {
                    String text = xmlReader.getElementText();
                    OMElement versionElement = factory.createOMElement(new QName("version"));
                    if (text != null) {
                        versionElement.setText(text);
                    }
                    root.addChild(versionElement);
                    // now go to the next element
                    do {
                        xmlReader.next();
                    } while (!xmlReader.isStartElement() && xmlReader.hasNext() &&
                            !(xmlReader.isEndElement() &&
                                    xmlReader.getLocalName().equals("resource")));
                }
                // setMediaType
                else if (localName.equals("mediaType")) {
                    String text = xmlReader.getElementText();
                    OMElement mediaTypeElement = factory.createOMElement(new QName("mediaType"));
                    if (text != null) {
                        mediaTypeElement.setText(text);
                    }
                    root.addChild(mediaTypeElement);
                    // now go to the next element
                    do {
                        xmlReader.next();
                    } while (!xmlReader.isStartElement() && xmlReader.hasNext() &&
                            !(xmlReader.isEndElement() &&
                                    xmlReader.getLocalName().equals("resource")));
                }
                // creator
                else if (localName.equals("creator")) {
                    String text = xmlReader.getElementText();
                    OMElement creatorElement = factory.createOMElement(new QName("creator"));
                    if (text != null) {
                        creatorElement.setText(text);
                    }
                    root.addChild(creatorElement);
                    // now go to the next element
                    do {
                        xmlReader.next();
                    } while (!xmlReader.isStartElement() && xmlReader.hasNext() &&
                            !(xmlReader.isEndElement() &&
                                    xmlReader.getLocalName().equals("resource")));
                }
                // createdTime
                else if (localName.equals("createdTime")) {
                    String text = xmlReader.getElementText();
                    OMElement createdTimeElement =
                            factory.createOMElement(new QName("createdTime"));
                    if (text != null) {
                        createdTimeElement.setText(text);
                    }
                    root.addChild(createdTimeElement);
                    // now go to the next element
                    do {
                        xmlReader.next();
                    } while (!xmlReader.isStartElement() && xmlReader.hasNext() &&
                            !(xmlReader.isEndElement() &&
                                    xmlReader.getLocalName().equals("resource")));
                }
                // createdTime
                else if (localName.equals("content")) {
                    // currently we are keeping the content within the root element, and remove it
                    // later. Before Carbon 3.0.0 the content was in the middle of the other
                    // resource attributes
                    String text = xmlReader.getElementText();
                    OMElement contentElement = factory.createOMElement(new QName("content"));
                    if (text != null) {
                        contentElement.setText(text);
                    }
                    root.addChild(contentElement);
                    // now go to the next element
                    do {
                        xmlReader.next();
                    } while (!xmlReader.isStartElement() && xmlReader.hasNext() &&
                            !(xmlReader.isEndElement() &&
                                    xmlReader.getLocalName().equals("resource")));
                }
                // setLastUpdater
                else if (localName.equals("lastUpdater")) {
                    String text = xmlReader.getElementText();
                    OMElement lastUpdaterElement =
                            factory.createOMElement(new QName("lastUpdater"));
                    if (text != null) {
                        lastUpdaterElement.setText(text);
                    }
                    root.addChild(lastUpdaterElement);
                    // now go to the next element
                    do {
                        xmlReader.next();
                    } while (!xmlReader.isStartElement() && xmlReader.hasNext() &&
                            !(xmlReader.isEndElement() &&
                                    xmlReader.getLocalName().equals("resource")));
                }
                // LastModified
                else if (localName.equals("lastModified")) {
                    String text = xmlReader.getElementText();
                    OMElement lastModifiedElement =
                            factory.createOMElement(new QName("lastModified"));
                    if (text != null) {
                        lastModifiedElement.setText(text);
                    }
                    root.addChild(lastModifiedElement);
                    // now go to the next element
                    do {
                        xmlReader.next();
                    } while (!xmlReader.isStartElement() && xmlReader.hasNext() &&
                            !(xmlReader.isEndElement() &&
                                    xmlReader.getLocalName().equals("resource")));
                }
                // get description
                else if (localName.equals("description")) {
                    String text = xmlReader.getElementText();
                    OMElement description = factory.createOMElement(new QName("description"));
                    if (text != null) {
                        description.setText(text);
                    }
                    root.addChild(description);
                    // now go to the next element
                    do {
                        xmlReader.next();
                    } while (!xmlReader.isStartElement() && xmlReader.hasNext() &&
                            !(xmlReader.isEndElement() &&
                                    xmlReader.getLocalName().equals("resource")));
                    // now go to the next element while
                    // (!xmlReader.isStartElement() && xmlReader.hasNext());
                }
                // get properties
                else if (localName.equals("properties")) {
                    // iterating trying to find the children..
                    OMElement properties = factory.createOMElement(new QName("properties"));
                    root.addChild(properties);
                    do {
                        xmlReader.next();
                    } while (!xmlReader.isStartElement() && xmlReader.hasNext() &&
                            !(xmlReader.isEndElement() &&
                                    xmlReader.getLocalName().equals("resource")));
                    while (xmlReader.hasNext() &&
                            xmlReader.getLocalName().equals("property")) {
                        String key = xmlReader.getAttributeValue(null, "key");
                        String text = xmlReader.getElementText();
                        OMElement property = factory.createOMElement(new QName("property"));
                        property.addAttribute("key", key, null);
                        properties.addChild(property);

                        if (text.equals("")) {
                            text = null;
                        }
                        if (text != null) {
                            property.setText(text);
                        }
                        do {
                            xmlReader.next();
                        } while (!xmlReader.isStartElement() && xmlReader.hasNext() &&
                                !(xmlReader.isEndElement() &&
                                        xmlReader.getLocalName().equals("resource")));
                    }
                    // getting comment information
                } else if (localName.equals("comments")) {
                    // iterating trying to find the children..
                    OMElement commentsElement = factory.createOMElement(new QName("comments"));
                    root.addChild(commentsElement);
                    do {
                        xmlReader.next();
                    } while (!xmlReader.isStartElement() && xmlReader.hasNext());
                    while (xmlReader.hasNext() &&
                            xmlReader.getLocalName().equals("comment")) {
                        do {
                            xmlReader.next();
                        } while (!xmlReader.isStartElement() && xmlReader.hasNext() &&
                                !(xmlReader.isEndElement() &&
                                        xmlReader.getLocalName().equals("resource")));

                        localName = xmlReader.getLocalName();
                        OMElement commentElement = factory.createOMElement(new QName("comment"));
                        commentsElement.addChild(commentElement);
                        while (xmlReader.hasNext() &&
                                (localName.equals("user") || localName.equals("text"))) {
                            if (localName.equals("user")) {
                                String text = xmlReader.getElementText();
                                if (text != null) {
                                    OMElement userElement =
                                            factory.createOMElement(new QName("user"));
                                    userElement.setText(text);
                                    commentElement.addChild(userElement);
                                }
                            } else if (localName.equals("text")) {
                                String text = xmlReader.getElementText();
                                if (text != null) {
                                    OMElement textElement =
                                            factory.createOMElement(new QName("text"));
                                    textElement.setText(text);
                                    commentElement.addChild(textElement);
                                }
                            }

                            do {
                                xmlReader.next();
                            } while (!xmlReader.isStartElement() && xmlReader.hasNext() &&
                                    !(xmlReader.isEndElement() &&
                                            xmlReader.getLocalName().equals("resource")));
                            if (xmlReader.hasNext()) {
                                localName = xmlReader.getLocalName();
                            }
                        }
                    }
                }
                // getting tagging information
                else if (localName.equals("taggings")) {
                    // iterating trying to find the children..
                    OMElement taggingsElement = factory.createOMElement(new QName("taggings"));
                    root.addChild(taggingsElement);
                    do {
                        xmlReader.next();
                    } while (!xmlReader.isStartElement() && xmlReader.hasNext() &&
                            !(xmlReader.isEndElement() &&
                                    xmlReader.getLocalName().equals("resource")));
                    while (xmlReader.hasNext() &&
                            xmlReader.getLocalName().equals("tagging")) {
                        do {
                            xmlReader.next();
                        } while (!xmlReader.isStartElement() && xmlReader.hasNext() &&
                                !(xmlReader.isEndElement() &&
                                        xmlReader.getLocalName().equals("resource")));

                        localName = xmlReader.getLocalName();

                        OMElement taggingElement = factory.createOMElement(new QName("tagging"));
                        taggingsElement.addChild(taggingElement);

                        while (xmlReader.hasNext() &&
                                (localName.equals("user") || localName.equals("date") ||
                                        localName.equals("tagName"))) {
                            if (localName.equals("user")) {
                                String text = xmlReader.getElementText();
                                if (text != null) {
                                    OMElement userElement =
                                            factory.createOMElement(new QName("user"));
                                    userElement.setText(text);
                                    taggingElement.addChild(userElement);
                                }
                            } else if (localName.equals("date")) {
                                String text = xmlReader.getElementText();
                                if (text != null) {
                                    OMElement dateElement =
                                            factory.createOMElement(new QName("date"));
                                    dateElement.setText(text);
                                    taggingElement.addChild(dateElement);
                                }
                            } else if (localName.equals("tagName")) {
                                String text = xmlReader.getElementText();
                                if (text != null) {
                                    OMElement tagNameElement =
                                            factory.createOMElement(new QName("tagName"));
                                    tagNameElement.setText(text);
                                    taggingElement.addChild(tagNameElement);
                                }
                            }
                            do {
                                xmlReader.next();
                            } while (!xmlReader.isStartElement() && xmlReader.hasNext() &&
                                    !(xmlReader.isEndElement() &&
                                            xmlReader.getLocalName().equals("resource")));
                            if (xmlReader.hasNext()) {
                                localName = xmlReader.getLocalName();
                            }
                        }
                    }
                }
                // getting rating information
                else if (localName.equals("ratings")) {
                    // iterating trying to find the children..
                    OMElement ratingsElement = factory.createOMElement(new QName("ratings"));
                    root.addChild(ratingsElement);
                    do {
                        xmlReader.next();
                    } while (!xmlReader.isStartElement() && xmlReader.hasNext() &&
                            !(xmlReader.isEndElement() &&
                                    xmlReader.getLocalName().equals("resource")));
                    while (xmlReader.hasNext() &&
                            xmlReader.getLocalName().equals("rating")) {
                        do {
                            xmlReader.next();
                        } while (!xmlReader.isStartElement() && xmlReader.hasNext());

                        localName = xmlReader.getLocalName();

                        OMElement ratingElement = factory.createOMElement(new QName("rating"));
                        ratingsElement.addChild(ratingElement);

                        while (xmlReader.hasNext() &&
                                (localName.equals("user") || localName.equals("date") ||
                                        localName.equals("rate"))) {
                            if (localName.equals("user")) {
                                String text = xmlReader.getElementText();
                                if (text != null) {
                                    OMElement userElement =
                                            factory.createOMElement(new QName("user"));
                                    userElement.setText(text);
                                    ratingElement.addChild(userElement);
                                }
                            } else if (localName.equals("date")) {
                                String text = xmlReader.getElementText();
                                if (text != null) {
                                    OMElement dateElement =
                                            factory.createOMElement(new QName("date"));
                                    dateElement.setText(text);
                                    ratingElement.addChild(dateElement);
                                }
                            } else if (localName.equals("rate")) {
                                String text = xmlReader.getElementText();
                                if (text != null) {
                                    OMElement rateElement =
                                            factory.createOMElement(new QName("rate"));
                                    rateElement.setText(text);
                                    ratingElement.addChild(rateElement);
                                }
                            }
                            do {
                                xmlReader.next();
                            } while (!xmlReader.isStartElement() && xmlReader.hasNext() &&
                                    !(xmlReader.isEndElement() &&
                                            xmlReader.getLocalName().equals("resource")));
                            if (xmlReader.hasNext()) {
                                localName = xmlReader.getLocalName();
                            }
                        }
                    }
                }
                // getting rating information
                else if (localName.equals("associations")) {
                    // iterating trying to find the children..
                    OMElement associationsElement =
                            factory.createOMElement(new QName("associations"));
                    root.addChild(associationsElement);
                    do {
                        xmlReader.next();
                    } while (!xmlReader.isStartElement() && xmlReader.hasNext() &&
                            !(xmlReader.isEndElement() &&
                                    xmlReader.getLocalName().equals("resource")));
                    while (xmlReader.hasNext() &&
                            xmlReader.getLocalName().equals("association")) {

                        do {
                            xmlReader.next();
                        } while (!xmlReader.isStartElement() && xmlReader.hasNext() &&
                                !(xmlReader.isEndElement() &&
                                        xmlReader.getLocalName().equals("resource")));

                        localName = xmlReader.getLocalName();

                        OMElement associationElement =
                                factory.createOMElement(new QName("association"));
                        associationsElement.addChild(associationElement);

                        while (xmlReader.hasNext() &&
                                (localName.equals("source") || localName.equals("destination") ||
                                        localName.equals("type"))) {
                            if (localName.equals("source")) {
                                String text = xmlReader.getElementText();
                                if (text != null) {
                                    OMElement sourceElement =
                                            factory.createOMElement(new QName("source"));
                                    sourceElement.setText(text);
                                    associationElement.addChild(sourceElement);
                                }
                            } else if (localName.equals("destination")) {
                                String text = xmlReader.getElementText();
                                if (text != null) {
                                    OMElement destinationElement =
                                            factory.createOMElement(new QName("destination"));
                                    destinationElement.setText(text);
                                    associationElement.addChild(destinationElement);
                                }
                            } else if (localName.equals("type")) {
                                String text = xmlReader.getElementText();
                                if (text != null) {
                                    OMElement typeElement =
                                            factory.createOMElement(new QName("type"));
                                    typeElement.setText(text);
                                    associationElement.addChild(typeElement);
                                }
                            }
                            do {
                                xmlReader.next();
                            } while (!xmlReader.isStartElement() && xmlReader.hasNext() &&
                                    !(xmlReader.isEndElement() &&
                                            xmlReader.getLocalName().equals("resource")));
                            if (xmlReader.hasNext()) {
                                localName = xmlReader.getLocalName();
                            }
                        }
                    }
                } else if (localName.equals("children") ||
                        localName.equals("resource")) {
                    // checking the children or content element to terminate the check.
                    break;
                } else {
                    // we do mind having unwanted elements, now go to the next element
                    break;
                }

                if ((xmlReader.isEndElement() && xmlReader.getLocalName().equals("resource"))) {
                    // here we come the end of the resource tag
                    break;
                }
            }
            return root;
        } catch (XMLStreamException e) {
            throw new SynchronizationException(
                    MessageCode.ERROR_IN_READING_STREAM_TO_CREATE_META_FILE);
        }
    }

    /**
     * This method creates the file that store the meta data of the current directory or file.
     *
     * @param fileName the name of the file.
     * @param metaData the meta data element.
     *
     * @throws SynchronizationException if the operation failed.
     */
    public static void createMetaFile(String fileName,
                                      OMElement metaData) throws SynchronizationException {

        try {
            File file = new File(fileName);

            String metaDirName = file.getParent();
            if (metaDirName != null) {
                File metaDir = new File(metaDirName);
                if (!metaDir.exists() && !metaDir.mkdir()) {
                    throw new SynchronizationException(MessageCode.ERROR_CREATING_META_FILE,
                            new String[]{"file name: " + fileName});
                }
            }
            if (!file.exists() && !file.createNewFile()) {
                throw new SynchronizationException(MessageCode.FILE_ALREADY_EXISTS,
                        new String[]{"file name: " + fileName});
            }

            FileOutputStream fileOut = null;
            try {
                fileOut = new FileOutputStream(file, false);
                metaData.serialize(fileOut);
            } finally {
                if (fileOut != null) {
                    fileOut.close();
                }
            }

        } catch (IOException e) {
            throw new SynchronizationException(MessageCode.ERROR_CREATING_META_FILE, e,
                    new String[]{"file name: " + fileName});
        } catch (XMLStreamException e) {
            throw new SynchronizationException(MessageCode.ERROR_WRITING_TO_META_FILE, e,
                    new String[]{"file name: " + fileName});
        }

    }

    /**
     * Returns the contents of the file in a byte array.
     *
     * @param file the file the to read
     *
     * @return the content of the file
     * @throws SynchronizationException if the operation failed.
     */
    public static byte[] getBytesFromFile(File file) throws SynchronizationException {

        InputStream is = null;
        try {
            try {
                is = new FileInputStream(file);
            } catch (FileNotFoundException e) {
                throw new SynchronizationException(MessageCode.FILE_TO_READ_IS_NOT_FOUND, e,
                        new String[]{"file name: " + file.getName()});
            }

            long length = file.length();

            // to ensure that file is not larger than Integer.MAX_VALUE.
            if (length > Integer.MAX_VALUE) {
                // File is too large
                throw new SynchronizationException(MessageCode.FILE_LENGTH_IS_TOO_LARGE,
                        new String[]{"file name: " + file.getName(),
                                "file length limit: " + Integer.MAX_VALUE});
            }

            // byte array to keep the data
            byte[] bytes = new byte[(int) length];

            int offset = 0;
            int numRead;
            try {
                while (offset < bytes.length
                        && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
                    offset += numRead;
                }
            } catch (IOException e) {
                throw new SynchronizationException(MessageCode.ERROR_IN_READING, e,
                        new String[]{"file name: " + file.getName()});
            }

            if (offset < bytes.length) {
                throw new SynchronizationException(MessageCode.ERROR_IN_COMPLETELY_READING,
                        new String[]{"file name: " + file.getName()});
            }
            return bytes;
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
            } catch (IOException ignore) {
                // We only want to make sure that the stream is closed. We don't quite need to worry
                // whether it failed or not, as this might happen due to another upstream exception.
            }
        }

    }

    /**
     * Method to obtain the XML representation of the meta information corresponding to the given
     * file. This method will first determine the path of the meta file for the given file-path, and
     * then obtain the corresponding XML representation using the {@link
     * #getOMElementFromMetaFile(String)} method.
     *
     * @param filePath the path to the file of which the meta information is required.
     *
     * @return An OM element containing the meta information.
     * @throws SynchronizationException if the operation failed.
     */
    public static OMElement getMetaOMElement(String filePath) throws SynchronizationException {
        File file = new File(filePath);
        if (!file.exists()) {
            return null;
        }
        String fileName = file.getName();
        String metaFilePath;
        if (file.isDirectory()) {
            metaFilePath = filePath + File.separator + SynchronizationConstants.META_DIRECTORY +
                    File.separator +
                    SynchronizationConstants.META_FILE_PREFIX +
                    SynchronizationConstants.META_FILE_EXTENSION;
        } else {
            String parentDirName = file.getParent();
            metaFilePath =
                    parentDirName + File.separator + SynchronizationConstants.META_DIRECTORY +
                            File.separator + SynchronizationConstants.META_FILE_PREFIX + fileName +
                            SynchronizationConstants.META_FILE_EXTENSION;
        }
        // check the existence of the meta directory
        File metaFile = new File(metaFilePath);
        if (!metaFile.exists()) {
            return null;
        }
        return Utils.getOMElementFromMetaFile(metaFilePath);
    }

    /**
     * Method to obtain the XML representation of the data contained in a meta file.
     *
     * @param metaFilePath the path to the meta file.
     *
     * @return An OM element containing the meta information.
     * @throws SynchronizationException if the operation failed.
     */
    public static OMElement getOMElementFromMetaFile(String metaFilePath) throws
            SynchronizationException {
        File metaFile = new File(metaFilePath);
        OMElement element = null;
        // if the file exists, just get it.
        FileInputStream directoryMetaFileStream = null;
        if (metaFile.exists()) {
            try {
                directoryMetaFileStream = new FileInputStream(metaFilePath);

                //create the parser
                XMLStreamReader parser = XMLInputFactory.newInstance()
                        .createXMLStreamReader(directoryMetaFileStream);
                //create the builder
                StAXOMBuilder builder = new StAXOMBuilder(parser);
                // get the element to restore
                element = builder.getDocumentElement().cloneOMElement();
                try {
                    directoryMetaFileStream.close();
                } catch (IOException e) {
                    throw new SynchronizationException(
                            MessageCode.ERROR_IN_CLOSING_META_FILE_STREAM, e,
                            new String[]{"meta file name: " + metaFilePath});
                }
            } catch (IOException e) {
                throw new SynchronizationException(MessageCode.ERROR_IN_READING_META_FILE,
                        e,
                        new String[]{"meta file name: " + metaFilePath});
            } catch (XMLStreamException e) {
                throw new SynchronizationException(
                        MessageCode.ERROR_IN_READING_META_FILE_STREAM,
                        e,
                        new String[]{"meta file name: " + metaFilePath});
            } finally {
                if (directoryMetaFileStream != null) {
                    try {
                        directoryMetaFileStream.close();
                    } catch (IOException ignore) {
                        // We cannot throw an exception in here because it would swallow the
                        // incoming exception if there are any. A potential user would in fact be
                        // interested in the incoming exception instead of this exception.
                    }
                }
            }
        }
        return element;
    }

    /**
     * Method to generate the XML content of a meta file. This method will require information about
     * the resource and details of who created it.
     *
     * @param isCollection whether the resource at the given path is a collection.
     * @param path         the path of the resource for which the meta information is generated.
     * @param username     the username of the creator.
     *
     * @return the meta information as an OM element.
     * @throws SynchronizationException if the operation failed.
     */
    public static OMElement createDefaultMetaFile(boolean isCollection,
                                                  String path,
                                                  String username)
            throws SynchronizationException {
        // if not provide the default details
        OMFactory factory = OMAbstractFactory.getOMFactory();
        OMElement root = factory.createOMElement(new QName("resource"));

        // adding path as an attribute
        root.addAttribute("path", path, null);

        String resourceName = RegistryUtils.getResourceName(path);
        root.addAttribute("name", resourceName, null);

        // adding isCollection as an attribute
        root.addAttribute("isCollection", isCollection ? "true" : "false", null);
        OMElement child;

        // guessing the media type by extension
        String mediaType = "unknown";
        int lastIndex = path.lastIndexOf('.');
        if (lastIndex > 0) {
            mediaType = path.substring(lastIndex + 1);
        }
        child = factory.createOMElement(new QName("mediaType"));
        child.setText(mediaType);
        root.addChild(child);

        // set creator
        child = factory.createOMElement(new QName("creator"));
        child.setText(username);
        root.addChild(child);

        // set createdTime
        long now = System.currentTimeMillis();
        child = factory.createOMElement(new QName("createdTime"));
        child.setText(Long.toString(now));
        root.addChild(child);

        // set updator
        child = factory.createOMElement(new QName("lastUpdater"));
        child.setText(username);
        root.addChild(child);

        // set LastModified
        child = factory.createOMElement(new QName("lastModified"));
        child.setText(Long.toString(now));
        root.addChild(child);

        // set Description
        child = factory.createOMElement(new QName("description"));
        root.addChild(child);

        // create a 0 version tag
        child = factory.createOMElement((new QName("version")));
        child.setText("0");
        root.addChild(child);

        return root;
    }

    /**
     * copying the contents of one file to another.
     *
     * @param source      source
     * @param destination destination
     *
     * @throws SynchronizationException throws if the operation failed.
     */
    public static void copy(File source, File destination) throws SynchronizationException {
        try {
            InputStream in = null;
            OutputStream out = null;
            try {
                in = new FileInputStream(source);
                out = new FileOutputStream(destination);

                // Transfer bytes from in to out
                byte[] buf = new byte[1024];
                int len;
                while ((len = in.read(buf)) > 0) {
                    out.write(buf, 0, len);
                }
            } finally {
                try {
                    if (in != null) {
                        in.close();
                    }
                } finally {
                    if (out != null) {
                        out.close();
                    }
                }
            }
        } catch (IOException e) {
            throw new SynchronizationException(MessageCode.ERROR_IN_COPYING, e,
                    new String[]{"source: " + source, "target: " + destination});
        }
    }

    /**
     * Method to extract the URL of the remote registry instance from the given URL.
     *
     * @param url 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.
     *
     * @return the URL of the remote instance, or null if the instance was local.
     */
    public static String getRegistryUrl(String url) {
        if (url.startsWith("/")) {
            // mean this is a local path..
            return null;
        }
        if (url.indexOf("/registry") > 0) {
            return url.substring(0, url.lastIndexOf("/registry") + "/registry".length());
        }
        return null;
    }

    /**
     * Method to extract the resource path from the given URL.
     *
     * @param url 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.
     *
     * @return the path of the resource on the registry.
     */
    public static String getPath(String url) {
        if (url.startsWith("/")) {
            // mean this is a local path..
            return url;
        }
        if (url.indexOf("/registry") > 0) {
            return url.substring(url.lastIndexOf("/registry") + "/registry".length());
        }
        return null;
    }

    /**
     * This method will obtain the encoded representation of the given resource name.
     *
     * @param resourceName the name of the resource.
     *
     * @return the encoded name.
     * @throws SynchronizationException if the operation failed.
     * @see URLEncoder
     */
    public static String encodeResourceName(String resourceName) throws SynchronizationException {
        String encodedName;
        try {
            encodedName = URLEncoder.encode(resourceName, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new SynchronizationException(MessageCode.ERROR_ENCODING_RESOURCE_NAME, e,
                    new String[]{"resource name: " + resourceName});
        }
        return encodedName;
    }

    /**
     * This method will obtain the decoded representation of the given encoded resource path.
     *
     * @param path the encoded path of the resource.
     *
     * @return the decoded path.
     * @throws SynchronizationException if the operation failed.
     * @see URLDecoder
     */
    public static String decodeFilename(String path) throws SynchronizationException {
        String decodedName;
        try {
            decodedName = URLDecoder.decode(path, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new SynchronizationException(MessageCode.ERROR_DECODING_PATH, e,
                    new String[]{"path: " + path});
        }
        return decodedName;

    }

    /**
     * This method will obtain the consent from the user to delete the specified file and meta file
     * (corresponding to the file), if the user agrees to.
     *
     * @param file     the file or directory to delete.
     * @param metaFile the meta file corresponding to the file or directory to delete.
     * @param callback the callback which is used to obtain the user's consent. If this parameter is
     *                 null, the file and the meta file will be deleted irrespective of the user's
     *                 choice.
     *
     * @return whether the operation succeeded or not.
     * @throws SynchronizationException if an error occurred during the operation.
     */
    public static boolean confirmDelete(File file, File metaFile, UserInputCallback callback)
            throws SynchronizationException {
        String filePath = file.getAbsolutePath();
        boolean isDirectory = file.isDirectory();

        boolean inputCode;

        if (callback == null) {
            // The default behaviour is to delete.
            inputCode = true;
        } else if (file.isDirectory()) {
            inputCode = callback.getConfirmation(new Message(
                    MessageCode.DIRECTORY_DELETE_CONFIRMATION,
                    new String[]{"file path: " + filePath}),
                    SynchronizationConstants.DELETE_CONFIRMATION_CONTEXT);
        } else {
            inputCode = callback.getConfirmation(new Message(
                    MessageCode.FILE_DELETE_CONFIRMATION,
                    new String[]{"file path: " + filePath}),
                    SynchronizationConstants.DELETE_CONFIRMATION_CONTEXT);
        }

        if (!inputCode) {
            // just continue;
            return false;
        }

        // if you come here it is for the permission to delete
        boolean deleted = deleteFile(file);
        if (!deleted) {
            throw new SynchronizationException(MessageCode.ERROR_IN_DELETING,
                    new String[]{"file path: " + filePath});
        }
        if (!isDirectory) {
            deleted = deleteFile(metaFile);
            if (!deleted) {
                throw new SynchronizationException(MessageCode.ERROR_IN_DELETING,
                        new String[]{"file path: " + metaFile.getAbsolutePath()});
            }
        }
        return true;
    }

    /**
     * This method deletes the specified file from the filesystem. If the given file-path
     * corresponds to a directory, the directory and everything under it (child files and
     * directories) will be recursively deleted in the process.
     *
     * @param file the file or directory to delete.
     *
     * @return true if the operation succeeded or false if it failed.
     */
    public static boolean deleteFile(File file) {
        if (file.isDirectory()) {
            String[] children = file.list();
            for (String child : children) {
                boolean success = deleteFile(new File(file, child));
                if (!success) {
                    return false;
                }
            }
        }
        return file.delete();
    }

    /**
     * Method to determine the files that are required to be cleaned up from meta information
     * directory and preserve only the given list of files. This method will determine all meta
     * files within the given directory that have no corresponding physical files on the filesystem.
     * This is used after a check-in operation has been propagated to ensure that the filesystem
     * will always remain consistent.
     *
     * @param directory       the meta information directory that requires cleaning up.
     * @param filesToPreserve the list of files to preserve.
     *
     * @return the list of files to be cleaned.
     */
    public static List<String> cleanUpDirectory(File directory, List<String> filesToPreserve) {
        List<String> filesToClean = new LinkedList<String>();
        if (directory.isDirectory()) {
            String[] children = directory.list();
            for (String child : children) {
                File file = new File(directory, child);
                String absoluteFilePath = file.getAbsolutePath();
                if (!filesToPreserve.contains(absoluteFilePath)) {
                    filesToClean.add(absoluteFilePath);
                }
            }
        }
        return filesToClean;
    }

    /**
     * Method to obtain the MD5 hash value for the given content.
     *
     * @param content the content as an array of bytes.
     *
     * @return the MD5 hash of the content.
     */
    public static String getMD5(byte[] content) {
        MessageDigest m;
        try {
            m = MessageDigest.getInstance("MD5");
        } catch (Exception e) {
            //String msg = "Error in generating the md5. ";
            //throw new Exception(msg, e);
            return null;
        }
        m.update(content, 0, content.length);

        return new BigInteger(1, m.digest()).toString(16);
    }

    /**
     * Determines whether the content of the given file has changed. If the given file is a
     * directory, this method will recursively test each file under this directory to determine
     * whether the content of any child, or grand child has changed.
     * <p/>
     * The change in content is determined using MD5 hash values written to the meta files during a
     * check-out or update. If the MD5 hash value of the given file was not found in its meta file,
     * this operation will assume that a change has been made, irrespective of whether the content
     * of the file changed or not.
     *
     * @param file the file to test for changes.
     *
     * @return true if the content has changed, or false if not.
     * @throws SynchronizationException if an error occurred during the operation.
     */
    public static boolean contentChanged(File file)
            throws SynchronizationException {
        return contentChanged(file, true);
    }

    // Method that actually checks for content changes. This needs to know whether the call is the
    // first-call to this method, or was it a recursive call.
    private static boolean contentChanged(File file, boolean isParent)
            throws SynchronizationException {
        if (!file.exists()) {
            // If we don't find a file, this is not a valid checkout.
            throw new SynchronizationException(MessageCode.CHECKOUT_BEFORE_CHECK_IN);
        } else if (file.isDirectory()) {
            File[] files = file.listFiles();
            if (files == null || files.length == 0) {
                // The meta information for this directory has not been found. Therefore, this is
                // a new directory.
                if (isParent) {
                    throw new SynchronizationException(MessageCode.CHECKOUT_BEFORE_CHECK_IN);
                }
                return true;
            }
            File metaFile = new File(file.getPath() + File.separator +
                    SynchronizationConstants.META_DIRECTORY);
            File[] metaFiles = metaFile.listFiles();
            if (metaFiles == null || metaFiles.length == 0) {
                // Though the meta directory exists, the meta information for the given directory
                // has not been found. Therefore, this is a new directory waiting to be checked in.
                return true;
            }
            // Child directories don't have meta files. Therefore, we need the number of children
            // that are not directories.
            int childFiles = 0;
            for (File child : files) {
                if (!child.isDirectory()) {
                    childFiles++;
                }
            }
            // We don't count the meta file corresponding to this directory.
            if ((metaFiles.length - 1) != childFiles) {
                // A file has been added or removed from this directory.
                return true;
            }
            for (File child : files) {
                // If the given child is not the meta directory, and if the content has changed,
                // the content of this directory has changed.
                if (!child.getPath().endsWith(SynchronizationConstants.META_DIRECTORY) &&
                        contentChanged(child, false)) {
                    return true;
                }
            }
            return false;
        }
        String parentDirName = file.getParent();
        String name = file.getName();
        String metaFilePath = parentDirName + File.separator +
                SynchronizationConstants.META_DIRECTORY + File.separator +
                SynchronizationConstants.META_FILE_PREFIX + name +
                SynchronizationConstants.META_FILE_EXTENSION;
        String currentMD5 = getMD5(getBytesFromFile(file));
        OMElement metaFileElement = getOMElementFromMetaFile(metaFilePath);
        String metaFileMD5 = null;
        if (metaFileElement != null) {
            metaFileMD5 = metaFileElement.getAttributeValue(new QName("md5"));
        }
        // We obtain the MD5 value of the file and compare it against the one saved in the meta file
        // to see whether any change has been done.
        return metaFileMD5 == null || !metaFileMD5.equals(currentMD5);
    }

    /**
     * Method to clean the embedded registry instance, after the synchronization operation. This
     * method should only be invoked if the synchronization happens at a client that terminates soon
     * after the execution of the synchronization operation, to prevent loss of activity logs.
     */
    public static void cleanEmbeddedRegistry() {
        RegistryContext registryContext = RegistryContext.getBaseInstance();
        if (registryContext != null) {
            LogWriter logWriter = registryContext.getLogWriter();
            if (logWriter != null) {
                logWriter.interrupt();
            }
        }
    }
}
TOP

Related Classes of org.wso2.carbon.registry.synchronization.Utils

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.