org.intalio.tempo.workflow.tas.nuxeo.NuxeoStorageStrategy.java Source code

Java tutorial

Introduction

Here is the source code for org.intalio.tempo.workflow.tas.nuxeo.NuxeoStorageStrategy.java

Source

/**
 * Copyright (c) 2005-2009 Intalio inc.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 * Intalio inc. - initial API and implementation
 */

package org.intalio.tempo.workflow.tas.nuxeo;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.Iterator;

import javax.xml.namespace.QName;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;

import org.apache.axiom.om.OMAttribute;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpConnectionManager;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.URIException;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.DeleteMethod;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.intalio.tempo.security.Property;
import org.intalio.tempo.workflow.tas.core.AttachmentMetadata;
import org.intalio.tempo.workflow.tas.core.StorageStrategy;
import org.intalio.tempo.workflow.tas.core.UnavailableAttachmentException;
import org.intalio.tempo.workflow.tas.sling.SlingStorageStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class NuxeoStorageStrategy implements StorageStrategy {

    private static final String NUXEO_FILE = "File";
    private static final String NUXEO_FOLDER = "Folder";
    private static final String NUXEO_DUBLINCORE_TITLE = "dublincore:title";
    private static final String NUXEO_DOC_TYPE = "docType";
    private static final String NUXEO_DOC_REF = "docRef";
    private static final String STRING_EMPTY = "";
    private static final String NUXEO_TYPE = "type";
    private static final String NUXEO_ID = "id";
    private static final String NUXEO_NAME = "name";
    private static final String NUXEO_DOCUMENT = "document";
    private static final String REST_BROWSE = "/browse";
    private static final String REST_UPLOAD = "/uploadFile";
    private static final String REST_CREATE = "/createDocument";
    private static final String REST_DELETE = "/delete";
    private static final String REST_DOWNLOAD = "/downloadFile";

    static Logger log = LoggerFactory.getLogger(SlingStorageStrategy.class);

    private String nuxeoBaseUrl = "http://localhost:9080/";
    // private String nuxeoUrl = nuxeoBaseUrl + "restAPI/default";
    private String repoName = "tempo";
    private String userName = "Administrator";
    private String password = "Administrator";

    // created on init()
    private HttpClient httpclient;
    // computed on init()
    private String repoId;

    // private boolean init = false;

    // NOT USED FOR NOW, but we could when we access versions
    // private String nuxeoPublicUrl = nuxeoBaseUrl +
    // "/admin/repository/default-domain/workspaces/" + repoName;

    public NuxeoStorageStrategy() throws Exception, IOException {

    }

    public void init() throws IOException {
        initHttpClient();
        try {
            String localRepoId = getWorkspacesURL(getNuxeoRestUrl(), "workspaces", "WorkspaceRoot");
            log.debug("LOCAL REPO" + localRepoId);
            repoId = getDocumentId(browse(localRepoId), this.repoName);
            if (repoId == null)
                repoId = createFolder(getNuxeoRestUrl() + "/" + localRepoId, this.repoName);
            log.debug("REPOURL:" + repoId);
            // init = true;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Everything we need to do to have an authenticated http client
     * 
     * @throws URIException
     */
    private void initHttpClient() throws URIException {
        httpclient = new HttpClient();
        HostConfiguration hostConfig = new HostConfiguration();
        org.apache.commons.httpclient.URI uri = new org.apache.commons.httpclient.URI(getNuxeoRestUrl(), false);
        hostConfig.setHost(uri);
        HttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
        HttpConnectionManagerParams params = new HttpConnectionManagerParams();
        int maxHostConnections = 20;
        params.setMaxConnectionsPerHost(hostConfig, maxHostConnections);
        connectionManager.setParams(params);
        httpclient = new HttpClient(connectionManager);
        httpclient.setHostConfiguration(hostConfig);
        Credentials creds = new UsernamePasswordCredentials(userName, password);
        AuthScope authScope = new AuthScope(hostConfig.getHost(), hostConfig.getPort());
        httpclient.getState().setCredentials(authScope, creds);
        httpclient.getParams().setAuthenticationPreemptive(true);
    }

    /**
     * Implement the interface for deleting a file
     */
    public void deleteAttachment(Property[] props, String url) throws UnavailableAttachmentException {
        try {
            // if (!init)
            init();
            String fileUrl = url.substring(0, url.indexOf(this.REST_DOWNLOAD));
            String newUri = fileUrl + REST_DELETE;
            log.debug("NUXEO DELETE:" + newUri);
            DeleteMethod method = new DeleteMethod(newUri);
            httpclient.executeMethod(method);
            // needed for proper httpclient handling
            // but we do not return the value
            // method.getResponseBodyAsString();
            method.releaseConnection();
        } catch (Exception e) {
            throw new UnavailableAttachmentException(e);
        }
    }

    /**
     * Store the attachment, implement the java interface
     */
    public String storeAttachment(Property[] properties, AttachmentMetadata metadata, InputStream payload)
            throws IOException {
        // if (!init)
        init();
        OMElement omEle = null;
        String encodedName = URLEncoder.encode(metadata.getFilename(), "utf-8");
        omEle = getCreateFileEle(getNuxeoRestUrl(), repoId, encodedName);
        log.debug("NUXEO ATTACH " + omEle.toString());
        if (omEle == null) {
            throw new IOException("Failed to create file :" + metadata.getFilename());
        }
        String fileId = getDocumentRef(omEle);
        String fileUrl = getNuxeoRestUrl() + "/" + fileId;
        String newUri = fileUrl + "/" + encodedName;
        uploadFile(newUri + REST_UPLOAD, payload);

        return fileUrl + REST_DOWNLOAD;
    }

    /**
     * Create a file reference in nuxeo, which does not contain the file, but
     * creates a file container so we can upload
     */
    private OMElement getCreateFileEle(String uri, String repoId, String fileName) throws IOException {
        String newUri = uri + "/" + repoId + REST_CREATE;
        GetMethod method = new GetMethod(newUri);

        NameValuePair[] pairs = new NameValuePair[2];
        pairs[0] = new NameValuePair(NUXEO_DOC_TYPE, NUXEO_FILE);
        String encodedName = URLEncoder.encode(fileName, "utf-8");
        pairs[1] = new NameValuePair(NUXEO_DUBLINCORE_TITLE, encodedName);

        method.setQueryString(pairs);
        httpclient.executeMethod(method);
        String value = method.getResponseBodyAsString();

        method.releaseConnection();
        return buildOMElement(value);
    }

    /**
     * Upload the binary content of the file to nuxeo
     */
    private void uploadFile(String uri, InputStream payload) throws IOException {
        PostMethod method = new PostMethod(uri);
        method.setRequestEntity(new InputStreamRequestEntity(payload));
        httpclient.executeMethod(method);
        // needed for proper httpclient handling
        // but we do not return the value
        // method.getResponseBodyAsString();
        method.releaseConnection();
    }

    /**
     * Creates a folder in nuxeo. We could expand that to create other things
     * like comments, ... This takes the place where to create the folder, and
     * the name of the folder to create, stored as dublin:core metadata
     */
    private String createFolder(String repoUri, String repoName) throws Exception {
        GetMethod method = new GetMethod(repoUri + REST_CREATE);
        log.debug("NUXEO CREATE FOLDER " + repoUri + " " + repoName);
        NameValuePair[] pairs = new NameValuePair[2];
        pairs[0] = new NameValuePair(NUXEO_DOC_TYPE, NUXEO_FOLDER);
        pairs[1] = new NameValuePair(NUXEO_DUBLINCORE_TITLE, repoName);
        method.setQueryString(pairs);
        httpclient.executeMethod(method);
        String value = method.getResponseBodyAsString();
        method.releaseConnection();
        OMElement omEle = buildOMElement(value);
        String docRef = omEle.getFirstChildWithName(new QName(STRING_EMPTY, NUXEO_DOC_REF)).getText();
        return docRef;
    }

    /**
     * Browse a container location in nuxeo. This is used in the code so we can
     * find duplicate folder. As such, we return the complete rest call xml
     */
    private OMElement browse(String folderId) throws Exception {
        GetMethod method = new GetMethod(getNuxeoRestUrl() + "/" + folderId + REST_BROWSE);
        httpclient.executeMethod(method);
        String value = method.getResponseBodyAsString();
        method.releaseConnection();
        OMElement ele = buildOMElement(value);
        return ele;
    }

    public String getNuxeoBaseUrl() {
        return nuxeoBaseUrl;
    }

    public void setNuxeoBaseUrl(String nuxeoBaseUrl) {
        this.nuxeoBaseUrl = nuxeoBaseUrl;
    }

    private String getNuxeoRestUrl() {
        return this.nuxeoBaseUrl + "restAPI/default";
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getRepoName() {
        return repoName;
    }

    public void setRepoName(String repoName) {
        this.repoName = repoName;
    }

    private String getWorkspacesURL(String repRootUri, String repName, String repType) throws Exception {
        String newUri = repRootUri + REST_BROWSE;
        String domainId = getDomainId(newUri);
        if (domainId == null) {
            throw new RuntimeException("Failed to find repository domain with url: " + repRootUri);
        }
        newUri = repRootUri + "/" + domainId + REST_BROWSE;
        log.debug("NUXEO BROWSE " + newUri);
        String repoId = getConfRepoId(newUri, repName, repType);
        if (repoId == null) {
            throw new RuntimeException("Failed to find repository with name=" + repName + " and type=" + repType);
        }
        return repoId;
    }

    private String getDomainId(String uri) throws Exception {
        GetMethod method = new GetMethod(uri);
        httpclient.executeMethod(method);
        String value = method.getResponseBodyAsString();
        method.releaseConnection();
        OMElement ele = buildOMElement(value);
        OMElement domainEle = getFirstChildWithName(ele, NUXEO_DOCUMENT);
        if (domainEle == null) {
            throw new RuntimeException("Failed to find repository domain with url: " + uri);
        }
        return getId(domainEle);
    }

    private String getConfRepoId(String uri, String name, String type) throws Exception {
        GetMethod method = new GetMethod(uri);

        httpclient.executeMethod(method);
        String value = method.getResponseBodyAsString();

        method.releaseConnection();
        return getId(buildOMElement(value), name, type);
    }

    private String getDocumentId(OMElement elem, String name) {
        Iterator<OMElement> children = elem.getChildrenWithLocalName(NUXEO_DOCUMENT);
        while (children.hasNext()) {
            OMElement child = children.next();
            OMAttribute attribute = child.getAttribute(new QName(STRING_EMPTY, NUXEO_NAME));
            String attributeValue = attribute.getAttributeValue();
            if (name.equalsIgnoreCase(attributeValue)) {
                return child.getAttributeValue(new QName(STRING_EMPTY, NUXEO_ID));
            }
        }
        return null;
    }

    private static String getId(OMElement omEle, String name, String type) {
        Iterator<OMElement> childEles = omEle.getChildElements();

        while (childEles.hasNext()) {
            OMElement childEle = childEles.next();

            QName nameQname = new QName(STRING_EMPTY, NUXEO_NAME);
            QName typeQname = new QName(STRING_EMPTY, NUXEO_TYPE);

            String curName = childEle.getAttributeValue(nameQname);
            String curType = childEle.getAttributeValue(typeQname);

            if ((name.equalsIgnoreCase(curName) && type.equalsIgnoreCase(curType))) {
                return getId(childEle);
            }
        }

        return null;
    }

    private static String getId(OMElement idEle) {
        QName idQname = new QName(STRING_EMPTY, NUXEO_ID);
        return idEle.getAttributeValue(idQname);
    }

    private String getDocumentRef(OMElement omEle) {
        OMElement docRefEle = getFirstChildWithName(omEle, NUXEO_DOC_REF);
        if (docRefEle != null) {
            return docRefEle.getText();
        }
        return null;
    }

    private static OMElement getFirstChildWithName(OMElement el, String name) {
        for (Iterator<OMElement> it = el.getChildElements(); it.hasNext();) {
            OMElement child = it.next();
            if (child.getLocalName().equals(name))
                return child;
        }
        return null;
    }

    private static OMElement buildOMElement(String xmlData) throws IOException {
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(xmlData.getBytes());
        XMLStreamReader parser;
        try {
            parser = XMLInputFactory.newInstance().createXMLStreamReader(byteArrayInputStream);
        } catch (XMLStreamException e) {
            throw new IOException(e.getMessage());
        }
        StAXOMBuilder builder = new StAXOMBuilder(parser);
        return builder.getDocumentElement();
    }

}