fr.openwide.talendalfresco.alfresco.NamePathServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for fr.openwide.talendalfresco.alfresco.NamePathServiceImpl.java

Source

/*
 * Copyright (C) 2008-2012 Open Wide SA
 *
 * This program is FREE software. You can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your opinion) 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, write to the Free Software Foundation,
 * Inc. ,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 * 
 * More information at http://knowledge.openwide.fr/bin/view/Main/AlfrescoETLConnector/
 *
 */
package fr.openwide.talendalfresco.alfresco;

import java.io.File;
import java.util.List;
import java.util.StringTokenizer;

import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.namespace.QName;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.repository.Repository;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.StringUtils;

/**
 * NamePathService impl
 * 
 * @author Marc Dutoo - Open Wide SA
 *
 */
public class NamePathServiceImpl implements NamePathService {

    protected static final Log logger = LogFactory.getLog(NamePathServiceImpl.class);

    protected NodeService nodeService;
    protected SearchService searchService;

    protected boolean alwaysUseDb = true;

    public NamePathServiceImpl() {

    }

    /**
     * Resolves given namePath using server File.separator
     * @see resolveNamePath(String, String)
     * @see getChildByPathName(String, NodeRef, QName)
     */
    public NodeRef resolveNamePath(String namePath) {
        return resolveNamePath(namePath, File.pathSeparator);
    }

    /**
     * Resolves given namePath from root
     * @see resolveNamePath(String, String, NodeRef)
     */
    public NodeRef resolveNamePath(String namePath, String pathDelimiter) {
        NodeRef companyHomeNodeRef = new NodeRef(Repository.getStoreRef(), Application.getCompanyRootId());
        return resolveNamePath(namePath, pathDelimiter, companyHomeNodeRef);
    }

    /**
     * Resolves given namePath using default cm:contains association
     * @see resolveNamePath(String, String, NodeRef, QName)
     * @see getChildByPathName(String, NodeRef, QName)
     */
    public NodeRef resolveNamePath(String namePath, String pathDelimiter, NodeRef rootNodeRef) {
        return resolveNamePath(namePath, pathDelimiter, rootNodeRef, ContentModel.ASSOC_CONTAINS);
    }

    /**
     * Resolves given namePath
     * @param targetLocationChildAssociationTypeQName
     * @see getChildByPathName(String, NodeRef, QName)
     */
    public NodeRef resolveNamePath(String namePath, String pathDelimiter, NodeRef rootNodeRef,
            QName targetLocationChildAssociationTypeQName) {
        StringTokenizer stok = new StringTokenizer(namePath, pathDelimiter);
        NodeRef currentNodeRef = rootNodeRef;
        while (stok.hasMoreTokens() && currentNodeRef != null) {
            String pathName = stok.nextToken();
            currentNodeRef = getChildByPathName(pathName, currentNodeRef, targetLocationChildAssociationTypeQName);
        }
        return currentNodeRef;
    }

    /**
     * @obsolete rather use db (nodeService), else custom lucene analyzers make it fail, e.g.
     * like those for French locale in 3.2 which remove ending "s".
     * Uses Lucene (rather than db) to avoid loading a distant subtree only to get the referenced node.
     * @param pathName must be not null and at least 2 chars long (lucene doesn't index single chars,
     * in this case use the other method or nodeService)
     * @param parentNodeRef
     * @return
     */
    public NodeRef getChildByPathName(String pathName, NodeRef parentNodeRef) {
        StringBuffer sbuf = new StringBuffer();
        sbuf.append("@cm\\:name:\"");
        sbuf.append(pathName);
        sbuf.append("\" AND ");
        sbuf.append("PRIMARYPARENT:\"");
        sbuf.append(parentNodeRef);
        sbuf.append("\"");
        ResultSet rset = searchService.query(parentNodeRef.getStoreRef(), SearchService.LANGUAGE_LUCENE,
                sbuf.toString());
        List<NodeRef> foundNodeRefs = (rset != null) ? rset.getNodeRefs() : null;
        if (foundNodeRefs == null || foundNodeRefs.isEmpty()) {
            // not found !
            return null;
        }
        NodeRef foundNodeRef = rset.getNodeRef(0);
        rset.close();
        return foundNodeRef;
    }

    /**
     * If not alwaysUseDb (which is not advised since custom lucene analyzers may make it fail,
     * e.g. like those for French locale in 3.2 which remove ending "s"), uses lucene when char
     * length pathName > 1 (else lucene can't) as an optimization.
     * @param pathName not null
     * @param parentNodeRef
     * @return
     */
    public NodeRef getChildByPathName(String pathName, NodeRef currentNodeRef,
            QName targetLocationChildAssociationTypeQName) {
        if (alwaysUseDb) {
            NodeRef foundNodeRef = nodeService.getChildByName(currentNodeRef,
                    targetLocationChildAssociationTypeQName, pathName);
            if (foundNodeRef != null && !nodeService.exists(foundNodeRef)) {
                // commit ends well but node not created because it did some underlaying non propagated transactions of its own
                logger.error("NamePathServiceImpl : zombie noderef " + foundNodeRef + " created (container "
                        + pathName + ")");
            }
            return foundNodeRef;
        }
        switch (pathName.length()) {
        case 0:
            // happens when //
            return null;
        case 1:
            // single char : use db
            return nodeService.getChildByName(currentNodeRef, targetLocationChildAssociationTypeQName, pathName);
        }
        return getChildByPathName(pathName, currentNodeRef);
    }

    /**
     * Returns the namePath, starts below the company home ("Alfresco").
     * Impl : could use a cache for better perfs, but Alfresco props are already cached (EHCache),
     * so for now it's ok like this.
     * @param importNodeContext
     * @return null if null or non existing noderef
     */
    public String getNamePath(NodeRef nodeRef, String pathDelimiter) {
        if (nodeRef == null || !nodeService.exists(nodeRef)) {
            return null;
        }
        java.util.ArrayList<String> pathNames = new java.util.ArrayList<String>();
        for (NodeRef currentParentRef = nodeRef; currentParentRef != null; currentParentRef = nodeService
                .getPrimaryParent(currentParentRef).getParentRef()) {
            String parentName = (String) nodeService.getProperty(currentParentRef, ContentModel.PROP_NAME);
            pathNames.add(0, parentName);
        }
        pathNames.remove(0); // remove root node
        pathNames.remove(0); // remove company node "Alfresco"
        return pathDelimiter + StringUtils.collectionToDelimitedString(pathNames, pathDelimiter);
    }

    public void setNodeService(NodeService nodeService) {
        this.nodeService = nodeService;
    }

    public void setSearchService(SearchService searchService) {
        this.searchService = searchService;
    }

    public void setAlwaysUseDb(boolean alwaysUseDb) {
        this.alwaysUseDb = alwaysUseDb;
    }

}