org.jlibrary.client.ui.repository.RepositoryHelper.java Source code

Java tutorial

Introduction

Here is the source code for org.jlibrary.client.ui.repository.RepositoryHelper.java

Source

/*
* jLibrary, Open Source Document Management System
* 
* Copyright (c) 2003-2006, Martn Prez Marin, Blandware (represented by
* Andrey Grebnev), and individual contributors as indicated by the
* @authors tag. See copyright.txt in the distribution for a full listing of
* individual contributors. All rights reserved.
* 
* This is free software; you can redistribute it and/or modify it
* under the terms of the Modified BSD License as published by the Free 
* Software Foundation.
* 
* This software 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 Modified
* BSD License for more details.
* 
* You should have received a copy of the Modified BSD License along with 
* this software; if not, write to the Free Software Foundation, Inc., 
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the
* FSF site: http://www.fsf.org.
*/
package org.jlibrary.client.ui.repository;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.TreeSet;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.jackrabbit.util.Text;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.jlibrary.cache.CacheUtils;
import org.jlibrary.client.Messages;
import org.jlibrary.client.extraction.MetaDataExtractor;
import org.jlibrary.client.i18n.LocaleService;
import org.jlibrary.core.entities.Author;
import org.jlibrary.core.entities.Category;
import org.jlibrary.core.entities.Directory;
import org.jlibrary.core.entities.Document;
import org.jlibrary.core.entities.DocumentMetaData;
import org.jlibrary.core.entities.Node;
import org.jlibrary.core.entities.Repository;
import org.jlibrary.core.entities.ResourceNode;
import org.jlibrary.core.entities.ServerProfile;
import org.jlibrary.core.entities.Ticket;
import org.jlibrary.core.entities.Types;
import org.jlibrary.core.factory.JLibraryServiceFactory;
import org.jlibrary.core.jcr.JLibraryConstants;
import org.jlibrary.core.properties.DocumentProperties;
import org.jlibrary.core.properties.InvalidPropertyTypeException;
import org.jlibrary.core.properties.PropertyNotFoundException;
import org.jlibrary.core.properties.ResourceNodeProperties;
import org.jlibrary.core.repository.RepositoryService;
import org.jlibrary.core.repository.exception.AuthorNotFoundException;
import org.jlibrary.core.repository.exception.RepositoryException;
import org.jlibrary.core.repository.exception.UnknownMethodException;
import org.jlibrary.core.search.extraction.ExtractionException;
import org.jlibrary.core.search.extraction.HTMLExtractor;
import org.jlibrary.core.search.extraction.HeaderMetaData;
import org.jlibrary.core.security.SecurityException;
import org.jlibrary.core.util.FileUtils;
import org.jlibrary.core.util.JLibraryAPIUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author martin
 *
 * This class will perform tasks that are useful in several actions, for example
 * creating a document structure, creating resources, etc.
 *
 * Having all this business logic centralized here prevents duplicate code and
 * by consequence promotes a less error-phrone basecode.
 */
public class RepositoryHelper {

    static Logger logger = LoggerFactory.getLogger(RepositoryHelper.class);

    private static NullProgressMonitor nullMonitor = new NullProgressMonitor();
    private static HTMLExtractor htmlExtractor = new HTMLExtractor();

    private static ArrayList addedResources = new ArrayList();

    /**
     * Creates a document into a repository
     *
     * @param repository Repository
     * @param parent Document's parent directory
     * @param file File that contains the document contents
     * @param crawlResources If <code>true</code> then jLibrary will try to extract
     * and create resources for this document.
     *
     * @throws RepositoryException If the document can't be created
     * @throws SecurityException If the user haven't enought rights to perform this operation
     */
    public static void createDocument(Repository repository, Directory parent, File file, boolean crawlResources)
            throws RepositoryException, SecurityException {

        createDocument(repository, parent, null, file, crawlResources);
    }

    /**
     * Creates a document into a repository
     *
     * @param repository Repository
     * @param parent Document's parent directory
     * @param properties Document properties. It can be <code>null</code> if 
     * you want jLibrary to perform the document data and metadata extraction 
     * automatically. Note that the content property must not be filled on 
     * the document's properties as is responsability of this method to grab 
     * it from the file and replace URL references if necessary.
     * @param file File that contains the document contents
     * @param crawlResources If <code>true</code> then jLibrary will try to extract
     * and create resources for this document.
     *
     * @return Document New created document
     *
     * @throws RepositoryException If the document can't be created
     * @throws SecurityException If the user haven't enought rights to perform this operation
     */
    public static Document createDocument(Repository repository, Directory parent, DocumentProperties properties,
            File file, boolean crawlResources) throws RepositoryException, SecurityException {

        addedResources.clear();

        ServerProfile profile = repository.getServerProfile();
        Ticket ticket = repository.getTicket();

        if (properties == null) {
            properties = createDocumentProperties(repository, file, parent,
                    repository.getRepositoryConfig().isExtractMetadata());
        }

        Integer typecode = (Integer) properties.getProperty(DocumentProperties.DOCUMENT_TYPECODE).getValue();

        RepositoryService service = JLibraryServiceFactory.getInstance(profile).getRepositoryService();
        boolean modifiedFile = false;
        // Create resources structure, currently only if the document is an HTML file
        if (file.exists() && crawlResources && Types.isResourceSensible(typecode)) {
            createResourcesStructure(repository, parent, file);
            if (!addedResources.isEmpty()) {
                try {
                    File tempFile = File.createTempFile("jlib", "html");
                    org.apache.commons.io.FileUtils.copyFile(file, tempFile);
                    file = tempFile;
                    modifiedFile = true;
                    htmlExtractor.changePaths(file, parent, addedResources);
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                }
            }
        }

        Document document;

        String apiVersion;
        boolean version1_2;
        try {
            apiVersion = service.getJLibraryAPIVersion();
            version1_2 = JLibraryAPIUtils.equalsOrExceeds(apiVersion, JLibraryConstants.VERSION_1_2);
        } catch (UnknownMethodException e) {
            // the server is old, it does not understand this
            version1_2 = false;
        }

        if (file.exists()) {
            // Stream content
            FileInputStream fis = null;
            try {
                fis = new FileInputStream(file);
                if (version1_2) {
                    // in this version, a method which allows to save both
                    // meta-data and data was added
                    document = service.createDocument(ticket, properties, fis);
                } else {
                    // using the old way: saving meta-data and data in the
                    // separate calls
                    document = service.createDocument(ticket, properties);
                    service.updateContent(ticket, document.getId(), fis);
                }
                if (modifiedFile) {
                    file.delete();
                }
            } catch (Exception e) {
                throw new RepositoryException(e);
            } finally {
                if (fis != null) {
                    try {
                        fis.close();
                    } catch (IOException e) {
                        logger.error(e.getMessage(), e);
                    }
                }
            }
        } else {
            // only the meta-data has to be created
            document = service.createDocument(ticket, properties);
        }

        EntityRegistry.getInstance().addNode(document);

        Iterator it = addedResources.iterator();
        while (it.hasNext()) {
            Node node = (Node) it.next();
            service.addResourceToDocument(ticket, node.getId(), document.getId());

            document.getResourceNodes().add(node);

            Directory resourceParent = (Directory) EntityRegistry.getInstance().getNode(node.getParent(),
                    node.getRepository());
            if (!resourceParent.getNodes().contains(node)) {
                resourceParent.getNodes().add(node);
                EntityRegistry.getInstance().addNode(node);
            }
        }

        parent.getNodes().add(document);
        return document;
    }

    /**
     * <p>Builds all the needed properties for a document. It will fill the 
     * metadata properties if specified. If the file exists, it will fill the 
     * contents. If the file does not exist, then it will create a stub 
     * document.</p>
     * 
     * <p>Note that this method won't create any resources for the document.</p>
     *
     * @param repository Repository
     * @param parent Document's parent directory
     * @param file File that contains the document contents
     * @param extractMetadata If <code>true</code> then jLibrary will try to 
     * extract the metadata. If <code>false</code> jLibrary will ignore 
     * document metadata
     *
     * @return DocumentProperties Properties of the created document
     *
     * @throws RepositoryException If the document properties cannot be 
     * obtained
     */
    public static DocumentProperties buildDocument(Repository repository, Directory parent, File file,
            boolean extractMetadata) throws RepositoryException {

        DocumentProperties properties = createDocumentProperties(repository, file, parent, extractMetadata);
        return properties;
    }

    private static void createResourcesStructure(Repository repository, Directory parent, File file)
            throws RepositoryException, SecurityException {

        String[] filenames = null;
        try {
            filenames = filterResourceNames(htmlExtractor.extractResources(file));
        } catch (ExtractionException e) {
            e.printStackTrace();
            logger.error(e.getMessage(), e);
            return;
        }
        for (int i = 0; i < filenames.length; i++) {
            String resourcePath = filenames[i];
            File resourceFile = new File(resourcePath);
            if (!resourceFile.exists()) {
                // try to add the parent's path
                filenames[i] = file.getParentFile().getAbsolutePath() + System.getProperty("file.separator")
                        + resourcePath;
                resourceFile = new File(filenames[i]);
                if (!resourceFile.exists()) {
                    continue;
                }
            }
            ResourceNode resource = createResourceFromFile(filenames[i], file.getAbsolutePath(), nullMonitor,
                    repository, parent);
            if (resource != null) {
                addedResources.add(resource);
            }
        }
    }

    private static String[] filterResourceNames(String[] filenames) {

        //TODO: Remove this Jackrabbit dependency
        for (int i = 0; i < filenames.length; i++) {
            filenames[i] = Text.unescape(filenames[i]);
        }
        return filenames;
    }

    public static Directory createDirectory(Repository repository, Directory dir, File file)
            throws RepositoryException, SecurityException {

        Directory parent = (Directory) EntityRegistry.getInstance().getNode(dir.getId(), dir.getRepository());
        String directoryName = file.getName();
        int indexColon = directoryName.indexOf(":");
        if (indexColon != -1) {
            directoryName = directoryName.substring(0, indexColon);
        }
        String description = Messages.getMessage("autogenerated_description");

        Directory directory = createDirectory(repository, parent, directoryName, description);
        return directory;
    }

    public static Directory createDirectory(Repository repository, Directory parent, String directoryName,
            String directoryDescription) throws RepositoryException, SecurityException {

        ServerProfile profile = repository.getServerProfile();
        Ticket ticket = repository.getTicket();

        RepositoryService service = JLibraryServiceFactory.getInstance(profile).getRepositoryService();
        Directory directory = service.createDirectory(ticket, directoryName, directoryDescription, parent.getId());
        parent.getNodes().add(directory);
        EntityRegistry.getInstance().addNode(directory);
        return directory;
    }

    public static Category findUnknownCategory(Repository repository) {

        if (repository.getCategories() != null) {
            Iterator it = repository.getCategories().iterator();
            while (it.hasNext()) {
                Category category = (Category) it.next();
                if (category.isUnknownCategory()) {
                    return category;
                }
            }
        }
        return null;
    }

    private static Author findAuthor(Repository repository, String authorName) {

        // Find author based in author text
        ServerProfile profile = repository.getServerProfile();
        Ticket ticket = repository.getTicket();

        RepositoryService service = JLibraryServiceFactory.getInstance(profile).getRepositoryService();

        Author author = null;
        try {
            author = service.findAuthorByName(ticket, authorName);
        } catch (AuthorNotFoundException anee) {
        } catch (RepositoryException e1) {
        }

        if (author == null) {
            return Author.UNKNOWN;
        }
        return author;
    }

    /**
     * Creates a resource node
     *
     * @param resourcePath Path to the resource file
     * @param documentPath Path to the document file. It can be <code>null</code>
     * if the document it has been already created
     * @param monitor Progress monitor to track resource addition
     * @param repository Repository
     * @param parent Parent node for the resource
     * 
     * @return ResourceNode Created resource node
     *
     * @throws RepositoryException If the resources can't be created
     * @throws SecurityException If the user doesn't have permissions to do this operation
     */
    private static ResourceNode createResourceFromFile(String resourcePath, String documentPath,
            IProgressMonitor monitor, Repository repository, Node parent)
            throws RepositoryException, SecurityException {

        Ticket ticket = repository.getTicket();
        ServerProfile profile = repository.getServerProfile();
        RepositoryService service = JLibraryServiceFactory.getInstance(profile).getRepositoryService();

        File resourceFile = new File(resourcePath);
        try {
            if ((documentPath != null) && !documentPath.equals("")) {
                String filteredResourcePath = StringUtils.replace(resourcePath, "\\", "/");
                filteredResourcePath = filteredResourcePath.substring(0, filteredResourcePath.lastIndexOf("/"));
                String filteredDocumentPath = StringUtils.replace(documentPath, "\\", "/");
                filteredDocumentPath = filteredDocumentPath.substring(0, filteredDocumentPath.lastIndexOf("/"));

                String subpath = StringUtils.difference(filteredDocumentPath, filteredResourcePath);

                // Remove the .. references

                if (subpath.length() > 0) {
                    // subpath. We must create the directories
                    String[] dirs = StringUtils.split(subpath, "/");
                    for (int i = 0; i < dirs.length; i++) {
                        String dirname = dirs[i];
                        if (dirname.equals(".")) {
                            continue;
                        }
                        if (dirname.equals("..")) {
                            if (parent.getParent() != null) {
                                parent = EntityRegistry.getInstance().getNode(parent.getParent(),
                                        parent.getRepository());
                            }
                            continue;
                        }

                        // Look if the directory already exists
                        boolean found = false;
                        Iterator it = parent.getNodes().iterator();
                        while (it.hasNext()) {
                            Node node = (Node) it.next();
                            if (!node.isDirectory())
                                continue;
                            if (node.getName().equalsIgnoreCase(dirname)) {
                                //catched
                                parent = node;
                                found = true;
                            }
                        }
                        if (!found) {
                            Node newParent = service.createDirectory(ticket, dirname,
                                    Messages.getMessage("autogenerated_description"), parent.getId());
                            EntityRegistry.getInstance().addNode(newParent);
                            parent.getNodes().add(newParent);
                            parent = newParent;
                        }
                    }
                }
            }
            String resourceName = resourceFile.getName();

            // Check if the resource already exists. We will look on the 
            // resources added for this document
            Iterator it = addedResources.iterator();
            while (it.hasNext()) {
                ResourceNode node = (ResourceNode) it.next();
                if (node.getName().equals(resourceName)) {
                    if (node.getParent().equals(parent.getId())) {
                        // Resource already exists
                        return node;
                    }
                }
            }

            // Check if the resource already exists. We will look now on the 
            // resources added to other documents
            it = parent.getNodes().iterator();
            while (it.hasNext()) {
                Node node = (Node) it.next();
                if (!node.isResource())
                    continue;
                ResourceNode resourceNode = (ResourceNode) node;
                if (resourceNode.getName().equals(resourceName)) {
                    return resourceNode;
                }
            }

            // It's a file. Create it
            monitor.subTask(
                    Messages.getAndParseValue("new_document_wizard_add_resource", "%1", resourceFile.getName()));
            monitor.internalWorked(1);

            ResourceNodeProperties resourceProperties = new ResourceNodeProperties();
            resourceProperties.addProperty(ResourceNodeProperties.RESOURCE_NAME, resourceName);
            resourceProperties.addProperty(ResourceNodeProperties.RESOURCE_TYPECODE,
                    Types.getTypeForFile(resourcePath));
            resourceProperties.addProperty(ResourceNodeProperties.RESOURCE_CONTENT,
                    IOUtils.toByteArray(new FileInputStream(resourceFile)));
            resourceProperties.addProperty(ResourceNodeProperties.RESOURCE_PARENT_ID, parent.getId());
            resourceProperties.addProperty(ResourceNodeProperties.RESOURCE_PATH,
                    FileUtils.buildPath((Directory) parent, resourceName));
            resourceProperties.addProperty(ResourceNodeProperties.RESOURCE_DESCRIPTION,
                    Messages.getMessage("autogenerated_description"));

            ResourceNode resource = service.createResource(ticket, resourceProperties);
            return resource;

        } catch (InvalidPropertyTypeException ipte) {
            logger.error(ipte.getMessage(), ipte);
            throw new RepositoryException(ipte);
        } catch (PropertyNotFoundException pnfe) {
            logger.error(pnfe.getMessage(), pnfe);
            throw new RepositoryException(pnfe);
        } catch (IOException ioe) {
            logger.error(ioe.getMessage(), ioe);
            throw new RepositoryException(ioe);
        }
    }

    /**
     * Creates a a resource from a file and adds it to a document
     *
     * @param repository Repository
     * @param parent Resource's parent directory
     * @param file File that contains the document contents
     * @param document Document in which the resource will be added
     * 
     * @return ResourceNode Created resource node
     *
     * @throws RepositoryException If the resource can't be created
     * @throws SecurityException If the user haven't enought rights to perform this operation
     */
    public static ResourceNode createResource(Repository repository, Directory parent, Document document, File file)
            throws RepositoryException, SecurityException {

        ResourceNode resource = createResource(repository, parent, file);

        ServerProfile profile = repository.getServerProfile();
        Ticket ticket = repository.getTicket();
        RepositoryService service = JLibraryServiceFactory.getInstance(profile).getRepositoryService();

        service.addResourceToDocument(ticket, resource.getId(), document.getId());

        return resource;
    }

    /**
     * Creates a a resource from a file
     *
     * @param repository Repository
     * @param parent Resource's parent directory
     * @param file File that contains the document contents
     * 
     * @return ResourceNode Created resource node
     *
     * @throws RepositoryException If the resource can't be created
     * @throws SecurityException If the user haven't enought rights to perform this operation
     */
    public static ResourceNode createResource(Repository repository, Directory parent, File file)
            throws RepositoryException, SecurityException {

        ServerProfile profile = repository.getServerProfile();
        Ticket ticket = repository.getTicket();

        ResourceNode resource = new ResourceNode();
        resource.setName(file.getName());
        resource.setTypecode(Types.getTypeForFile(file.getName()));
        resource.setDescription(Messages.getMessage("metadata_extracted"));
        resource.setNodes(new TreeSet());
        resource.setParent(parent.getId());
        resource.setPath(file.getAbsolutePath());
        resource.setRepository(parent.getRepository());
        resource.setImportance(Node.IMPORTANCE_MEDIUM);
        resource.setCreator(ticket.getUser().getId());
        resource.setSize(new BigDecimal((double) file.length()));
        resource.setDate(new Date());

        FileInputStream fis = null;
        try {
            RepositoryService service = JLibraryServiceFactory.getInstance(profile).getRepositoryService();
            ResourceNodeProperties resProperties = resource.dumpProperties();
            resource = service.createResource(ticket, resProperties);

            try {
                fis = new FileInputStream(file);
                service.updateContent(ticket, resource.getId(), fis);
                CacheUtils.addFileToCache(file, resource);
            } catch (Exception e) {
                throw new RepositoryException(e);
            }

            EntityRegistry.getInstance().addNode(resource);

            parent.getNodes().add(resource);

        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException ioe) {
                    logger.error(ioe.getMessage(), ioe);
                }
            }
        }
        return resource;
    }

    private static DocumentProperties createDocumentProperties(Repository repository, File file, Directory parent,
            boolean extractMetadata) {

        Ticket ticket = repository.getTicket();

        Category unknownCategory = findUnknownCategory(repository);
        // Try to extract metadata
        HeaderMetaData header = null;
        if (extractMetadata) {
            MetaDataExtractor.extractMetaData(file.getAbsolutePath());
        }
        Document document = new Document();
        document.setTypecode(Types.getTypeForFile(file.getName()));
        DocumentMetaData metadata = new DocumentMetaData();

        if ((header != null) && (header.getAuthor() != null) && (!header.getAuthor().equals(""))) {
            metadata.setAuthor(findAuthor(repository, header.getAuthor()));
        } else {
            metadata.setAuthor(Author.UNKNOWN);
        }
        if ((header != null) && (header.getKeywords() != null) && (!header.getKeywords().equals(""))) {
            metadata.setKeywords(header.getKeywords());
        } else {
            metadata.setKeywords("");
        }
        if ((header != null) && (header.getLanguage() != null) && (!header.getLanguage().equals(""))
                && LocaleService.getInstance().isSupportedDocumentLanguage(header.getLanguage())) {
            metadata.setLanguage(header.getLanguage());
        } else {
            metadata.setLanguage(DocumentMetaData.UNKNOWN_LANGUAGE);
        }
        if ((header != null) && (header.getTitle() != null) && (!header.getTitle().equals(""))) {
            metadata.setTitle(header.getTitle());
            if (document.getTypecode() == Types.HTML_DOCUMENT) {
                // It's very common that related web pages have the same title
                document.setName(file.getName());
            } else {
                document.setName(header.getTitle());
            }
        } else {
            metadata.setTitle(file.getName());
            document.setName(file.getName());
        }
        metadata.setUrl("file://" + file.getAbsolutePath());
        metadata.setDate(new Date(file.lastModified()));

        if ((header != null) && (header.getDescription() != null) && (!header.getDescription().equals(""))) {
            document.setDescription(header.getDescription());
        } else {
            document.setDescription(Messages.getMessage("metadata_extracted"));
        }
        document.setExternal(false);
        document.setMetaData(metadata);
        document.setNodes(new TreeSet());
        document.setNotes(new HashSet());
        document.setParent(parent.getId());
        document.setReference(false);
        document.setRepository(parent.getRepository());
        document.setImportance(Node.IMPORTANCE_MEDIUM);
        document.setCreator(ticket.getUser().getId());

        document.setSize(new BigDecimal((double) file.length()));
        document.setDate(new Date());

        document.setMetaData(metadata);

        String path = FileUtils.buildPath(parent, file.getName());
        document.setPath(path);

        DocumentProperties docProperties = document.dumpProperties();
        if (!(document.getTypecode() == Types.FOLDER) && !(document.getTypecode() == Types.IMAGE_DOCUMENT)
                && !(document.getTypecode() == Types.OTHER)) {
            if (unknownCategory != null) {
                try {
                    docProperties.addProperty(DocumentProperties.DOCUMENT_ADD_CATEGORY, unknownCategory.getId());
                } catch (PropertyNotFoundException e) {
                    logger.error(e.getMessage(), e);
                } catch (InvalidPropertyTypeException e) {
                    logger.error(e.getMessage(), e);
                }
            }
        }
        return docProperties;
    }

}