org.exoplatform.services.jcr.ext.artifact.ArtifactManagingServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.exoplatform.services.jcr.ext.artifact.ArtifactManagingServiceImpl.java

Source

/**
 * Copyright (C) 2003-2007 eXo Platform SAS.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License
 * as published by the Free Software Foundation; either version 3
 * of the License, or (at your option) any later version.
    
 * This program 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 General Public License for more details.
    
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see<http://www.gnu.org/licenses/>.
 */

package org.exoplatform.services.jcr.ext.artifact;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.exoplatform.container.xml.InitParams;
import org.exoplatform.container.xml.PropertiesParam;
import org.exoplatform.services.jcr.RepositoryService;
import org.exoplatform.services.jcr.access.AccessControlEntry;
import org.exoplatform.services.jcr.config.RepositoryConfigurationException;
import org.exoplatform.services.jcr.core.ExtendedNode;
import org.exoplatform.services.jcr.core.ManageableRepository;
import org.exoplatform.services.jcr.core.nodetype.ExtendedNodeTypeManager;
import org.exoplatform.services.jcr.core.nodetype.NodeTypeDataManager;
import org.exoplatform.services.jcr.ext.common.SessionProvider;
import org.exoplatform.services.jcr.ext.registry.RegistryEntry;
import org.exoplatform.services.jcr.ext.registry.RegistryService;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.picocontainer.Startable;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.PathNotFoundException;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.nodetype.NodeType;
import javax.jcr.query.Query;
import javax.jcr.query.QueryManager;
import javax.jcr.query.QueryResult;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;

/**
 * Created by The eXo Platform SAS .<br/>
 * Service responsible for Administration Maven repository the served JCR structure inside
 * workspaceName is: rootPath (maven-root)/ ---part-of-group-folder1/ (nt:folder + exo:groupId)
 * ---part-of-group-foldern/ ------artifact-root-folder/(nt:folder + exo:artifactId)
 * ---------maven-metadata.xml(nt:file) ---------maven-metadata.xml.sha1(nt:file)
 * ---------artifact-version-folder/(nt:folder + exo:versionId) ------------artifactId-version.jar
 * (nt:file + exo:mavenjar / nt:resource) ------------artifactId-version.jar.sha1 (nt:file +
 * exo:mavensha1 / nt:resource ) ------------artifactId-version.pom (nt:file + exo:mavenpom /
 * nt:resource) ------------artifactId-version.pom.sha1 (nt:file + exo:mavensha1/ (nt:resource)
 * ------------maven-metadata.xml (nt:file +exo:mavenmetadata / (nt:resource )
 * ------------maven-metadata.xml.sha1(nt:file + exo:mavensha1 / (nt:resource)
 * 
 * @author Gennady Azarenkov
 * @author Volodymyr Krasnikov
 * @version $Id: $
 */
public class ArtifactManagingServiceImpl implements ArtifactManagingService, Startable {
    private static final int BUFFER = 4096;

    private static final String STRING_TERMINATOR = "*";

    private static final String NT_FILE = "artifact-nodetypes.xml";

    private static final String SERVICE_NAME = "ArtifactManaging";

    private RepositoryService repositoryService;

    private RegistryService registryService;

    private SessionProvider sessionProvider;

    private InitParams initParams;

    private String repoWorkspaceName;

    private String rootNodePath;

    private static final Log LOG = ExoLogger.getLogger(ArtifactManagingServiceImpl.class);

    private Map<String, String> mimeMap = new Hashtable<String, String>();

    private List<String> listErrorPom = new ArrayList<String>();

    /**
     * @param params
     * @param repositoryService
     * @param registryService
     * @throws RepositoryConfigurationException
     */
    public ArtifactManagingServiceImpl(InitParams initParams, RepositoryService repositoryService,
            RegistryService registryService) throws RepositoryConfigurationException {
        this.repositoryService = repositoryService;
        this.registryService = registryService;

        if (initParams == null) {
            throw new RepositoryConfigurationException("Init parameters expected !!!");
        }

        this.initParams = initParams;

        setDefaultMimes();
    }

    /**
     * without registry service
     * 
     * @param params
     * @param repositoryService
     * @throws RepositoryConfigurationException
     */
    public ArtifactManagingServiceImpl(InitParams params, RepositoryService repositoryService)
            throws RepositoryConfigurationException {
        this(params, repositoryService, null);
    }

    /*
     * (non-Javadoc)
     * @see org.exoplatform.services.jcr.ext.maven.ArtifactManagingService#addArtifact
     * (org.exoplatform.services.jcr.ext.common.SessionProvider,
     * org.exoplatform.services.jcr.ext.maven.ArtifactDescriptor, java.io.InputStream)
     */
    public void addArtifact(SessionProvider sp, ArtifactDescriptor artifact, InputStream jarIStream,
            InputStream pomIStream) throws RepositoryException {

        Session session = currentSession(sp);
        Node rootNode = (Node) session.getItem(rootNodePath);

        Node groupId_tail = createGroupIdLayout(rootNode, artifact);

        Node artifactId_node = createArtifactIdLayout(groupId_tail, artifact);

        Node version_node = createVersionLayout(artifactId_node, artifact);

        if (version_node != null) { // returns if the same node sibling appears
            importResource(version_node, jarIStream, "jar", artifact);
            importResource(version_node, pomIStream, "pom", artifact);
        }

        session.save();

    }

    /*
     * (non-Javadoc)
     * @see org.exoplatform.services.jcr.ext.maven.ArtifactManagingService#exportArtifacts
     * (org.exoplatform.services.jcr.ext.common.SessionProvider,
     * org.exoplatform.services.jcr.ext.maven.FolderDescriptor, java.io.OutputStream)
     */
    public void exportArtifacts(SessionProvider sp, FolderDescriptor parentFolder, OutputStream out)
            throws RepositoryException, FileNotFoundException {

        Session session = currentSession(sp);
        Node parentNode;
        if (rootNodePath.length() > 1) {
            parentNode = (Node) session.getItem(rootNodePath + "/" + parentFolder.getAsPath());
        } else {
            parentNode = (Node) session.getItem("/" + parentFolder.getAsPath());
        }

        LOG.info("Write repository to zipped stream");

        ZipOutputStream zout = new ZipOutputStream(new BufferedOutputStream(out, BUFFER));
        try {
            mapRepositoryToZipStream(parentNode, zout);
            zout.flush();
            zout.close();
        } catch (IOException e) {
            LOG.error("Cannot write to zip stream", e);
        }

    }

    public void exportArtifacts(SessionProvider sp, FolderDescriptor parentFolder, File destFolder)
            throws RepositoryException, FileNotFoundException {

        Session session = currentSession(sp);
        Node parentNode;
        if (rootNodePath.length() > 1) {
            parentNode = (Node) session.getItem(rootNodePath + "/" + parentFolder.getAsPath());
        } else {
            parentNode = (Node) session.getItem("/" + parentFolder.getAsPath());
        }
        mapRepositoryToFilefs(parentNode, destFolder);
    }

    private void mapRepositoryToFilefs(Node parentNode, File parentFolder) throws RepositoryException {
        NodeIterator folderIterator = parentNode.getNodes();
        while (folderIterator.hasNext()) {
            Node folder = folderIterator.nextNode();
            if (folder.isNodeType("exo:artifact")) {
                File levelfolder = new File(parentFolder.getAbsoluteFile() + File.separator + folder.getName());
                levelfolder.mkdir();
                mapRepositoryToFilefs(folder, levelfolder); // recursive call
            } else if (folder.isNodeType("exo:file")) {
                File content = new File(parentFolder + File.separator + folder.getName());

                FileOutputStream fout = null;
                try {
                    fout = new FileOutputStream(content);
                    Node dataNode = folder.getNode("jcr:content");

                    Property data = dataNode.getProperty("jcr:data");
                    Property lastModified = dataNode.getProperty("jcr:lastModified");
                    content.setLastModified(lastModified.getLong());
                    IOUtils.copy(data.getStream(), fout);

                } catch (FileNotFoundException e) {
                    LOG.error("!!Can't create content fo file", e);
                } catch (IOException e) {
                    LOG.error("!!Can't write content fo file", e);
                } finally {
                    IOUtils.closeQuietly(fout);
                }
            }
        }
    }

    private void mapRepositoryToZipStream(Node parentNode, ZipOutputStream zout)
            throws RepositoryException, IOException {

        NodeIterator folderIterator = parentNode.getNodes();
        while (folderIterator.hasNext()) {
            Node folder = folderIterator.nextNode();
            if (folder.isNodeType("exo:artifact")) {
                String entryName = parentNode.getPath() + File.separator + folder.getName();
                ZipEntry entry = new ZipEntry(entryName + "/");

                zout.putNextEntry(entry);

                mapRepositoryToZipStream(folder, zout);

            } else if (folder.isNodeType("exo:file")) {

                String entryName = parentNode.getPath() + File.separator + folder.getName();
                ZipEntry entry = new ZipEntry(entryName);

                if (LOG.isDebugEnabled()) {
                    LOG.debug("Zipping " + entryName);
                }

                Node dataNode = folder.getNode("jcr:content");
                Property data = dataNode.getProperty("jcr:data");
                InputStream in = data.getStream();

                Property lastModified = dataNode.getProperty("jcr:lastModified");

                entry.setTime(lastModified.getLong());
                entry.setSize(in.available());
                zout.putNextEntry(entry);

                int count;
                byte[] buf = new byte[BUFFER];
                while ((count = in.read(buf, 0, BUFFER)) != -1) {
                    zout.write(buf, 0, count);
                }
                zout.flush();
                in.close();
            }
        }
    }

    /*
     * (non-Javadoc)
     * @see org.exoplatform.services.jcr.ext.maven.ArtifactManagingService#getDescriptors
     * (org.exoplatform.services.jcr.ext.common.SessionProvider,
     * org.exoplatform.services.jcr.ext.maven.FolderDescriptor)
     */
    public List<Descriptor> getDescriptors(SessionProvider sp, FolderDescriptor parentFolder)
            throws RepositoryException {
        LOG.info("Get child nodes to : " + parentFolder.getAsString());

        Session session = currentSession(sp);

        session.refresh(true);

        Node rootNode = (Node) session.getItem(rootNodePath);
        String strPath = parentFolder.getAsString();

        Node targetNode;
        if (strPath.equals("/")) {
            targetNode = rootNode;
        } else {
            targetNode = rootNode.getNode(strPath.substring(1));
        }
        LOG.info(targetNode.getPath());
        NodeType[] a = targetNode.getMixinNodeTypes();
        StringBuilder mixins = new StringBuilder();
        for (NodeType type : a) {
            mixins.append(type.getName()).append(" ");
        }
        LOG.info("**** Mixins : " + mixins.toString());

        LOG.info("**** Workspace : " + session.getWorkspace().getName());

        List<Descriptor> childNodes = new ArrayList<Descriptor>();
        for (NodeIterator iterator = targetNode.getNodes(); iterator.hasNext();) {
            // descriptor holds names of all child nodes than makes up artifact
            // coordinates.
            Node node = iterator.nextNode();

            if (node.isNodeType("nt:folder") || node.isNodeType("nt:file")) {
                Descriptor descriptor = new FolderDescriptor(node.getName());
                childNodes.add(descriptor);
            }
        }

        return (childNodes.size() == 0) ? null : childNodes;
    }

    /*
     * (non-Javadoc)
     * @see org.exoplatform.services.jcr.ext.maven.ArtifactManagingService#importArtifacts
     * (org.exoplatform.services.jcr.ext.common.SessionProvider, java.io.InputStream)
     */
    public void importArtifacts(SessionProvider sp, InputStream in)
            throws RepositoryException, FileNotFoundException {
        LOG.info("Extract repository to temporary folder");
        String path = System.getProperty("java.io.tmpdir") + File.separator + "maven2";
        File temporaryFolder = new File(getUniqueFilename(path));
        if (!temporaryFolder.mkdir()) {
            throw new FileNotFoundException("Cannot create temporary folder");
        }
        ZipEntry entry;
        ZipInputStream zipIn = new ZipInputStream(new BufferedInputStream(in));
        try {
            while ((entry = zipIn.getNextEntry()) != null) {

                if (!(entry.isDirectory()
                        && new File(temporaryFolder + File.separator + entry.getName()).mkdir())) {
                    int count;
                    byte data[] = new byte[BUFFER];
                    File file = new File(temporaryFolder + File.separator + entry.getName());

                    FileUtils.touch(file);

                    FileOutputStream fos = new FileOutputStream(file);
                    BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER);
                    while ((count = zipIn.read(data, 0, BUFFER)) != -1) {
                        dest.write(data, 0, count);
                    }
                    dest.flush();
                    dest.close();
                }

            }
        } catch (IOException e) {
            LOG.error("Cannot get zip entry from stream", e);
        } finally {
            IOUtils.closeQuietly(zipIn);
            IOUtils.closeQuietly(in);
        }

        // main part - copy to JCR from temp folder
        // use uploading artifacts from local folder.

        importArtifacts(sp, temporaryFolder);
        try {
            FileUtils.deleteDirectory(temporaryFolder);
        } catch (IOException e) {
            LOG.error("Cannot remove temporary folder", e);
        }

    }

    /*
     * (non-Javadoc)
     * @see org.exoplatform.services.jcr.ext.maven.ArtifactManagingService#importArtifacts
     * (org.exoplatform.services.jcr.ext.common.SessionProvider, java.io.File)
     */
    public void importArtifacts(SessionProvider sp, File folder) throws RepositoryException, FileNotFoundException {
        if (!folder.exists())
            throw new FileNotFoundException("Source folder expected");
        try {
            this.listErrorPom.clear();
            importFilesToJCR(sp, folder);
        } catch (Exception e) {
            LOG.error("Exception during uploading local folder to JCR", e);
        }
    }

    /*
     * This method provides adding to JCR artifacts. this means that jar-files and appropriate pom
     * files would be added. Main logic: scan all files & if it is a pair jar/pom -add it.
     */
    private void importFilesToJCR(SessionProvider sp, File folder) throws Exception {

        for (File file : folder.listFiles(new DefaultFileFilter())) {

            if (file.isDirectory()) {
                importFilesToJCR(sp, file);
            }

            String ext = FilenameUtils.getExtension(file.getAbsolutePath());
            if (ext.equals("pom")) {
                String basename = FilenameUtils.removeExtension(file.getAbsolutePath());
                File jarfile = new File(basename.concat(".jar"));

                if (jarfile.exists()) {
                    // get descripting from pom file
                    try {
                        ArtifactDescriptor artifact = ArtifactDescriptor.createFromPomfile(file);
                        InputStream jarIStream = new FileInputStream(jarfile);
                        InputStream pomIStream = new FileInputStream(file);

                        addArtifact(sp, artifact, jarIStream, pomIStream);
                    } catch (org.xml.sax.SAXParseException e) {
                        // throw new ArtifactDescriptorException(FilenameUtils.getName(file.getAbsolutePath()));
                        this.listErrorPom.add(FilenameUtils.getName(file.getAbsolutePath()));
                        continue;
                    }
                }
            }
        }
    }

    /*
     * According JCR structure, version Node holds all actual data: jar, pom and ckecksums Removing
     * that node is removing all content and artifact indeed!
     * @see org.exoplatform.services.jcr.ext.maven.ArtifactManagingService#removeArtifact
     * (org.exoplatform.services.jcr.ext.common.SessionProvider,
     * org.exoplatform.services.jcr.ext.maven.ArtifactDescriptor)
     */
    public void removeArtifact(SessionProvider sp, Descriptor artifact) throws RepositoryException {
        Session session = currentSession(sp);
        Node root = (Node) session.getItem(rootNodePath);

        String pathToRemove = "";

        if (rootNodePath.length() > 1) {
            if (rootNodePath.endsWith("/"))
                pathToRemove = rootNodePath + artifact.getAsPath();
            else
                pathToRemove = rootNodePath + "/" + artifact.getAsPath();
        } else {
            pathToRemove = "/" + artifact.getAsPath();
        }

        if (LOG.isDebugEnabled()) {
            LOG.debug("Remove node: " + pathToRemove);
        }

        Node rmNode = (Node) session.getItem(pathToRemove);

        // while (rmNode != root) {
        // Node parent = rmNode.getParent();
        rmNode.remove();
        // if (!parent.hasNodes())
        // rmNode = parent;
        // else
        // break;
        // }
        session.save();
    }

    public List getPermission(SessionProvider sp, Descriptor artifact) throws RepositoryException {

        Session session = currentSession(sp);
        String pathToCheck = "";

        if (rootNodePath.length() > 1) { // artifact root is some real node
            if (rootNodePath.endsWith("/"))
                pathToCheck = rootNodePath + artifact.getAsPath();
            else
                pathToCheck = rootNodePath + "/" + artifact.getAsPath();
        } else {
            pathToCheck = "/" + artifact.getAsPath(); // "/" - is root path
        }

        LOG.debug("Checking Permission on node: " + pathToCheck);
        ExtendedNode rmNode = (ExtendedNode) session.getItem(pathToCheck);
        List<AccessControlEntry> list = rmNode.getACL().getPermissionEntries();
        return list;
    }

    public void changePermission(SessionProvider sp, Descriptor artifact, String identity, String[] permissions,
            boolean delete) throws RepositoryException {

        Session session = currentSession(sp);
        String pathToChange = "";

        if (rootNodePath.length() > 1) { // artifact root is some real node
            if (rootNodePath.endsWith("/"))
                pathToChange = rootNodePath + artifact.getAsPath();
            else
                pathToChange = rootNodePath + "/" + artifact.getAsPath();
        } else {
            pathToChange = "/" + artifact.getAsPath(); // "/" - is root path
        }

        LOG.debug("Changing Permission on node: " + pathToChange);

        ExtendedNode chNode = (ExtendedNode) session.getItem(pathToChange);
        if (!chNode.isNodeType("exo:privilegeable")) {
            if (chNode.canAddMixin("exo:privilegeable"))
                chNode.addMixin("exo:privilegeable");
            else
                throw new RepositoryException("Can't add mixin");
        }
        // log.info("PERMS-SIZE:" + permissions.length);
        try {
            if (!delete)
                chNode.setPermission(identity, permissions);
            else {
                if (permissions.length > 0) {
                    for (int i = 0; i < permissions.length; i++)
                        chNode.removePermission(identity, permissions[i]);
                } else {
                    chNode.removePermission(identity);
                }
            }
        } catch (RepositoryException e) {
            LOG.error("Cannot change permissions", e);
        }

        session.save();
    }

    /*
     * (non-Javadoc)
     * @see org.exoplatform.services.jcr.ext.maven.ArtifactManagingService#searchArtifacts
     * (org.exoplatform.services.jcr.ext.common.SessionProvider,
     * org.exoplatform.services.jcr.ext.maven.SearchCriteria)
     */
    public List<Descriptor> searchArtifacts(SessionProvider sp, SearchCriteria criteria)
            throws RepositoryException {
        Session session = currentSession(sp);

        session.refresh(true);
        session.save();

        String param = criteria.getContainsExpr();
        String pathConstraint = "";
        if (rootNodePath.length() > 1) { // artifact root is some real node
            if (rootNodePath.endsWith("/"))
                pathConstraint = rootNodePath + "%/" + param + "[%]";
            else
                pathConstraint = rootNodePath + "/%/" + param + "[%]";
        } else {
            pathConstraint = "/%/" + param + "[%]"; // artifact root is workspace root
        }
        // node !!

        String sqlQuery = String.format("SELECT * FROM nt:folder WHERE jcr:path LIKE '%s' ", pathConstraint);

        LOG.info(sqlQuery);
        QueryManager manager = session.getWorkspace().getQueryManager();
        Query query = manager.createQuery(sqlQuery, Query.SQL);

        QueryResult queryResult = query.execute();
        NodeIterator iterator = queryResult.getNodes();

        List<Descriptor> preciseNode = new ArrayList<Descriptor>();
        while (iterator.hasNext()) {

            Node candidate = iterator.nextNode();

            Descriptor descriptor = new FolderDescriptor(candidate.getPath());
            preciseNode.add(descriptor);

        }

        return preciseNode;
    }

    /*
     * (non-Javadoc)
     * @see org.picocontainer.Startable#start()
     */
    public void start() {
        // responsible for:
        // 1. reading parameters (such as repoWorkspaceName, repoPath) from
        // registryService (if present) or init params
        // 2. initializing artifact service Registry Entry if registryService is
        // present
        // if Entry is not initialized yet (first launch)
        // 3. initializing maven root if not initialized

        if (LOG.isDebugEnabled()) {
            LOG.debug("Starting ArtifactManagingService ...");
        }

        sessionProvider = SessionProvider.createSystemProvider();

        try {
            InputStream xml = getClass().getResourceAsStream(NT_FILE);
            ManageableRepository rep = repositoryService.getCurrentRepository();
            rep.getNodeTypeManager().registerNodeTypes(xml, ExtendedNodeTypeManager.IGNORE_IF_EXISTS,
                    NodeTypeDataManager.TEXT_XML);
            readParamsFromRegistryService(sessionProvider);
            prepareRootNode(sessionProvider, rootNodePath);
        } catch (PathNotFoundException e) {
            try {
                readParamsFromFile();
                writeParamsToRegistryService(sessionProvider);

                prepareRootNode(sessionProvider, rootNodePath);
            } catch (RepositoryException exc) {
                LOG.error("Cannot write init configuration to RegistryService", exc);
            } catch (IOException exc) {
                LOG.error("Cannot write init configuration to RegistryService", exc);
            } catch (SAXException exc) {
                LOG.error("Cannot write init configuration to RegistryService", exc);
            } catch (ParserConfigurationException exc) {
                LOG.error("Cannot write init configuration to RegistryService", exc);
            }
        } catch (RepositoryException e) {
            LOG.error("Error while register nodetypes/checking existance", e);
        } finally {
            sessionProvider.close();
        }
    }

    /*
     * (non-Javadoc)
     * @see org.picocontainer.Startable#stop()
     */
    public void stop() {
    }

    private Session currentSession(SessionProvider sp) throws RepositoryException {
        return sp.getSession(repoWorkspaceName, repositoryService.getCurrentRepository());
    }

    private void prepareRootNode(SessionProvider sp, String path) throws RepositoryException {
        Session session = currentSession(sp);
        Node current_root = session.getRootNode();
        for (String folder : path.split("/")) {
            if (!current_root.hasNode(folder)) {
                current_root.addNode(folder);
            }
            current_root = current_root.getNode(folder);
        }
        session.save();
        if (!session.getItem(path).isNode())
            throw new RepositoryException("Maven root node is not been initialized");
    }

    // this function creates hierarchy in JCR storage acording to groupID
    // parameter : com.google.code...
    private Node createGroupIdLayout(Node rootNode, ArtifactDescriptor artifact) throws RepositoryException {
        FolderDescriptor groupId = artifact.getGroupId();
        List<String> struct_groupId = new ArrayList<String>();

        String[] items = groupId.getAsPath().split("/");

        for (String subString : items) {
            struct_groupId.add(subString);
        }
        Node groupIdTail = rootNode;

        for (Iterator<String> iterator = struct_groupId.iterator(); iterator.hasNext();) {
            String name = iterator.next();
            Node levelNode;
            // Node do not has such child nodes
            if (!groupIdTail.hasNode(name)) {
                levelNode = groupIdTail.addNode(name, "nt:folder");
                levelNode.addMixin("exo:groupId");
            } else {
                levelNode = groupIdTail.getNode(name);
            }
            groupIdTail = levelNode;
        }

        return groupIdTail;
    }

    private Node createArtifactIdLayout(Node groupId_NodeTail, ArtifactDescriptor artifact)
            throws RepositoryException {
        String artifactId = artifact.getArtifactId();
        Node artifactIdNode;
        if (!groupId_NodeTail.hasNode(artifactId)) {
            artifactIdNode = groupId_NodeTail.addNode(artifactId, "nt:folder");
            artifactIdNode.addMixin("exo:artifactId");
            artifactIdNode.setProperty("exo:versionList", new String[] {
                    ArtifactManagingServiceImpl.STRING_TERMINATOR, ArtifactManagingServiceImpl.STRING_TERMINATOR });
        } else {
            artifactIdNode = groupId_NodeTail.getNode(artifactId);
        }
        return artifactIdNode;
    }

    private Node createVersionLayout(Node artifactId, ArtifactDescriptor artifact) throws RepositoryException {
        String version = artifact.getVersionId();

        if (artifactId.hasNode(version))
            return null;

        Node currentVersion = artifactId.addNode(version, "nt:folder");
        currentVersion.addMixin("exo:versionId");

        return currentVersion;
    }

    // this method used for writing to repo jars, poms and their checksums
    private void importResource(Node parentNode, InputStream file_in, String resourceType,
            ArtifactDescriptor artifact) throws RepositoryException {
        // Note that artifactBean been initialized within constructor
        // resourceType can be jar, pom, metadata

        String filename;
        if (resourceType.equals("metadata")) {
            filename = "maven-metadata.xml";
        } else {
            filename = String.format("%s-%s.%s", artifact.getArtifactId(), artifact.getVersionId(), resourceType);
        }

        OutputStream fout = null;
        File tmp_file = null;
        try {
            String tmpFilename = getUniqueFilename(filename);
            tmp_file = File.createTempFile(tmpFilename, null);
            fout = new FileOutputStream(tmp_file);
            IOUtils.copy(file_in, fout);
            fout.flush();
        } catch (FileNotFoundException e) {
            LOG.error("Cannot create .tmp file for storing artifact", e);
        } catch (IOException e) {
            LOG.error("IO exception on .tmp file for storing artifact", e);
        } finally {
            IOUtils.closeQuietly(file_in);
            IOUtils.closeQuietly(fout);
        }

        writePrimaryContent(parentNode, filename, resourceType, tmp_file);
        writeChecksum(parentNode, filename, tmp_file, "SHA1");

        try {
            // and collect all garbage : temporary files
            FileUtils.forceDelete(tmp_file);
        } catch (IOException e) {
            LOG.error("Cannot delete tmp file", e);
        }

    }

    private void writePrimaryContent(Node parentNode, String filename, String resourceType, File srcFile)
            throws RepositoryException {

        String mimeType = getRelativeMimeType(resourceType);
        Node nodeResourceFile = parentNode.addNode(filename, "nt:file");

        String mixinType = "exo:maven".concat(resourceType);
        if (nodeResourceFile.canAddMixin(mixinType))
            nodeResourceFile.addMixin(mixinType);
        try {
            InputStream file_is = new FileInputStream(srcFile);

            Node content = nodeResourceFile.addNode("jcr:content", "nt:resource");
            content.setProperty("jcr:mimeType", mimeType);
            content.setProperty("jcr:lastModified", Calendar.getInstance());
            content.setProperty("jcr:data", file_is);

            IOUtils.closeQuietly(file_is);

        } catch (FileNotFoundException e) {
            LOG.error("Cannot read from .tmp resource file", e);
        }
    }

    private void writeChecksum(Node parentNode, String filename, File srcFile, String algorithm)
            throws RepositoryException {
        Node nodeChecksumFile = parentNode.addNode(filename.concat("." + algorithm.toLowerCase()), "nt:file");

        String mixinType = "exo:maven".concat(algorithm.toLowerCase());
        if (nodeChecksumFile.canAddMixin(mixinType)) {
            nodeChecksumFile.addMixin(mixinType);
        }
        try {

            FileInputStream fileInputStream = new FileInputStream(srcFile);
            String checksum = CRCGenerator.getChecksum(fileInputStream, algorithm);

            InputStream checksum_is = new ByteArrayInputStream(checksum.getBytes());
            String mimeType = "text/plain";

            Node content = nodeChecksumFile.addNode("jcr:content", "nt:resource");
            content.setProperty("jcr:mimeType", mimeType);
            content.setProperty("jcr:lastModified", Calendar.getInstance());
            content.setProperty("jcr:data", checksum_is);

            IOUtils.closeQuietly(checksum_is);
        } catch (FileNotFoundException e) {
            LOG.error("Cannot read from .tmp resource file", e);
        } catch (IOException e) {
            LOG.error("Cannot read from .tmp resource file", e);
        } catch (NoSuchAlgorithmException e) {
            LOG.error("No such algorithm for generating checksums", e);
        }
    }

    protected File createSingleMetadata(String groupId, String artifactId, String version)
            throws FileNotFoundException {
        File temp = null;
        try {
            String filename = getUniqueFilename("maven-metadata.xml");
            temp = File.createTempFile(filename, null);

            OutputStream os = new FileOutputStream(temp);
            XMLOutputFactory factory = XMLOutputFactory.newInstance();
            XMLStreamWriter writer = factory.createXMLStreamWriter(os);
            try {
                writer.writeStartDocument("UTF-8", "1.0");
                writer.writeStartElement("metadata");

                writer.writeStartElement("groupId");
                writer.writeCharacters(groupId);
                writer.writeEndElement();

                writer.writeStartElement("artifactId");
                writer.writeCharacters(artifactId);
                writer.writeEndElement();

                writer.writeStartElement("version");
                writer.writeCharacters(version);
                writer.writeEndElement();

                writer.writeEndElement();
                writer.writeEndDocument();
            } finally {
                writer.flush();
                writer.close();
                os.close();
            }
        } catch (XMLStreamException e) {
            LOG.error("Error on creating metadata - XML", e);
        } catch (IOException e) {
            LOG.error("Error on creating metadata - FILE", e);
        }
        return (temp != null && temp.exists()) ? temp : null;
    }

    protected File createMultiMetadata(String groupId, String artifactId, String current_version,
            List<String> v_list) throws FileNotFoundException {
        File temp = null;
        try {
            String filename = getUniqueFilename("maven-metadata.xml");
            temp = File.createTempFile(filename, null);

            OutputStream os = new FileOutputStream(temp);
            XMLOutputFactory factory = XMLOutputFactory.newInstance();
            XMLStreamWriter writer = factory.createXMLStreamWriter(os);
            try {
                writer.writeStartDocument("UTF-8", "1.0");
                writer.writeStartElement("metadata");

                writer.writeStartElement("groupId");
                writer.writeCharacters(groupId);
                writer.writeEndElement();

                writer.writeStartElement("artifactId");
                writer.writeCharacters(artifactId);
                writer.writeEndElement();

                String elderVersion;
                if (v_list.size() > 0) {
                    Collections.sort(v_list); // sort list
                    elderVersion = v_list.get(0); // get first element
                } else
                    elderVersion = current_version;
                v_list.add(current_version);

                writer.writeStartElement("version");
                writer.writeCharacters(elderVersion);
                writer.writeEndElement();

                writer.writeStartElement("versions");
                writer.writeStartElement("versioning");

                for (Iterator<String> iterator = v_list.iterator(); iterator.hasNext();) {
                    writer.writeStartElement("version");
                    writer.writeCharacters(iterator.next());
                    writer.writeEndElement();
                }

                writer.writeEndElement();
                writer.writeEndElement();

                writer.writeEndElement();
                writer.writeEndDocument();
            } finally {
                writer.flush();
                writer.close();
                os.close();
            }
        } catch (XMLStreamException e) {
            LOG.error("Error on creating metadata - XML", e);
        } catch (IOException e) {
            LOG.error("Error on creating metadata - FILE", e);
        }
        return (temp != null && temp.exists()) ? temp : null;
    }

    private String getRelativeMimeType(String key) {
        return (String) mimeMap.get(key);
    }

    private void setDefaultMimes() {
        mimeMap.put("jar", "application/java-archive");
        mimeMap.put("pom", "text/xml");
        // mimeMap.put("metadata", "text/xml");
    }

    private String getUniqueFilename(String basename) {
        String suffix = ((Double) Math.random()).toString().substring(2, 7);
        return basename + "." + suffix;
    }

    /**
     * Read parameters from RegistryService.
     * 
     * @param sessionProvider
     *          The SessionProvider
     * @throws RepositoryException
     * @throws PathNotFoundException
     */
    private void readParamsFromRegistryService(SessionProvider sessionProvider)
            throws PathNotFoundException, RepositoryException {
        String entryPath = RegistryService.EXO_SERVICES + "/" + SERVICE_NAME + "/" + "workspace";
        RegistryEntry registryEntry = registryService.getEntry(sessionProvider, entryPath);
        Document doc = registryEntry.getDocument();
        Element element = doc.getDocumentElement();
        repoWorkspaceName = getAttributeSmart(element, "value");

        entryPath = RegistryService.EXO_SERVICES + "/" + SERVICE_NAME + "/" + "rootNode";
        registryEntry = registryService.getEntry(sessionProvider, entryPath);
        doc = registryEntry.getDocument();
        element = doc.getDocumentElement();
        rootNodePath = getAttributeSmart(element, "value");

        LOG.info("Workspace from RegistryService: " + repoWorkspaceName);
        LOG.info("RootNode from RegistryService: " + rootNodePath);
    }

    /**
     * Write parameters to RegistryService.
     * 
     * @param sessionProvider
     *          The SessionProvider
     * @throws ParserConfigurationException
     * @throws SAXException
     * @throws IOException
     * @throws RepositoryException
     */
    private void writeParamsToRegistryService(SessionProvider sessionProvider)
            throws IOException, SAXException, ParserConfigurationException, RepositoryException {

        Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
        Element root = doc.createElement(SERVICE_NAME);
        doc.appendChild(root);

        Element element = doc.createElement("workspace");
        setAttributeSmart(element, "value", repoWorkspaceName);
        root.appendChild(element);

        element = doc.createElement("rootNode");
        setAttributeSmart(element, "value", rootNodePath);
        root.appendChild(element);

        RegistryEntry serviceEntry = new RegistryEntry(doc);
        registryService.createEntry(sessionProvider, RegistryService.EXO_SERVICES, serviceEntry);
    }

    /**
     * Get attribute value.
     * 
     * @param element
     *          The element to get attribute value
     * @param attr
     *          The attribute name
     * @return Value of attribute if present and null in other case
     */
    private String getAttributeSmart(Element element, String attr) {
        return element.hasAttribute(attr) ? element.getAttribute(attr) : null;
    }

    /**
     * Set attribute value. If value is null the attribute will be removed.
     * 
     * @param element
     *          The element to set attribute value
     * @param attr
     *          The attribute name
     * @param value
     *          The value of attribute
     */
    private void setAttributeSmart(Element element, String attr, String value) {
        if (value == null) {
            element.removeAttribute(attr);
        } else {
            element.setAttribute(attr, value);
        }
    }

    /**
     * Get parameters which passed from the configuration file.
     * 
     * @throws RepositoryConfigurationException
     * 
     * @throws RepositoryConfigurationException
     */
    private void readParamsFromFile() {
        PropertiesParam props = initParams.getPropertiesParam("artifact.workspace");

        if (props == null) {
            throw new IllegalArgumentException("Property parameters 'locations' expected");
        }

        repoWorkspaceName = props.getProperty("workspace");
        rootNodePath = props.getProperty("rootNode");

        LOG.info("Workspace from configuration file: " + repoWorkspaceName);
        LOG.info("RootNode from configuration file: " + rootNodePath);
    }

    public List getListErrors() {
        return listErrorPom;
    }

}