org.nuxeo.ecm.platform.sync.server.webservices.WSSynchroServerModule.java Source code

Java tutorial

Introduction

Here is the source code for org.nuxeo.ecm.platform.sync.server.webservices.WSSynchroServerModule.java

Source

/*
 * (C) Copyright 2009 Nuxeo SA (http://nuxeo.com/) and contributors.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser General Public License
 * (LGPL) version 2.1 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl.html
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * Contributors:
 *     mariana
 */
package org.nuxeo.ecm.platform.sync.server.webservices;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;

import javax.annotation.Resource;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.xml.namespace.QName;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.soap.Addressing;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.cxf.wsdl.EndpointReferenceUtils;
import org.joda.time.DateTime;
import org.joda.time.format.ISODateTimeFormat;
import org.nuxeo.ecm.core.api.ClientException;
import org.nuxeo.ecm.core.api.CoreSession;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.DocumentModelList;
import org.nuxeo.ecm.core.api.DocumentRef;
import org.nuxeo.ecm.core.api.IdRef;
import org.nuxeo.ecm.core.api.Lock;
import org.nuxeo.ecm.core.api.PathRef;
import org.nuxeo.ecm.core.api.UnrestrictedSessionRunner;
import org.nuxeo.ecm.core.api.VersionModel;
import org.nuxeo.ecm.core.api.facet.VersioningDocument;
import org.nuxeo.ecm.core.api.impl.DocumentModelListImpl;
import org.nuxeo.ecm.core.api.security.SecurityConstants;
import org.nuxeo.ecm.core.schema.types.primitives.DateType;
import org.nuxeo.ecm.platform.query.api.PageProviderDefinition;
import org.nuxeo.ecm.platform.query.api.PageProviderService;
import org.nuxeo.ecm.platform.sync.adapter.SynchronizableDocument;
import org.nuxeo.ecm.platform.sync.server.tuple.ContextDataInfo;
import org.nuxeo.ecm.platform.sync.server.tuple.FlagedDocumentSnapshot;
import org.nuxeo.ecm.platform.sync.server.tuple.FlagedDocumentSnapshotFactory;
import org.nuxeo.ecm.platform.sync.server.tuple.NuxeoSynchroTuple;
import org.nuxeo.runtime.api.Framework;

/**
 * @author mcedica
 */

@WebService
@Addressing
public class WSSynchroServerModule implements StatefulWebServiceManagement {

    public static final QName Q_NAME = new QName("http://webservices.server.sync.platform.ecm.nuxeo.org/",
            "WSSynchroServerModuleService");

    private static final Log log = LogFactory.getLog(WSSynchroServerModule.class);

    private static Map<String, BasicSession> sessions = new WeakHashMap<>();

    @Resource
    protected WebServiceContext wsContext;

    public WSSynchroServerModule() {
    }

    public WSSynchroServerModule(BasicSession _session) {
        sessions.put(_session.toString(), _session);
        // session = _session;
    }

    protected BasicSession getSession() {
        MessageContext ctx = wsContext.getMessageContext();
        String refId = EndpointReferenceUtils.getEndpointReferenceId(ctx);
        return sessions.get(refId);
    }

    @WebMethod(operationName = "getAvailableDocumentListWithQuery")
    public NuxeoSynchroTuple[] getAvailableDocumentListWithQuery(String queryName) throws ClientException {
        List<NuxeoSynchroTuple> availableTuples = new ArrayList<NuxeoSynchroTuple>();
        NuxeoSynchroTuple tuple = null;
        Calendar modificationDate = null;
        List<String> domainNames = new ArrayList<String>();
        try {
            getSession().login();
            CoreSession documentManager = getSession().getCoreSession();
            // invalidate cache
            documentManager.save();

            String queryString = getInlinedQuery(queryName);
            if (queryString == null) {
                queryString = getQuery(queryName);
            }
            DocumentModelList availableDocs = documentManager.query(queryString);
            DocumentModelList unrestrictedDocs = new DocumentModelListImpl();
            List<String> availableDocIds = new ArrayList<String>();
            for (DocumentModel documentModel : availableDocs) {
                if (documentModel.getType().equals("Domain")) {
                    domainNames.add(documentModel.getName());
                }
                availableDocIds.add(documentModel.getId());
            }
            for (DocumentModel documentModel : availableDocs) {
                if (documentManager.hasPermission(documentModel.getRef(), SecurityConstants.READ)) {
                    modificationDate = (Calendar) documentModel.getPropertyValue("dc:modified");
                    long modificationTime = modificationDate != null ? modificationDate.getTimeInMillis() : 0;
                    SynchronizableDocument syncDoc = documentModel.getAdapter(SynchronizableDocument.class);
                    tuple = new NuxeoSynchroTuple(documentModel.getId(), documentModel.getId(), syncDoc.getId(),
                            documentModel.getType(), documentModel.getPathAsString(), modificationTime,
                            documentModel.isProxy(), documentModel.isVersion());
                    tuple.setContextData(
                            getContextData(documentManager, documentModel, availableDocIds, unrestrictedDocs));
                    availableTuples.add(tuple);
                } else {
                    unrestrictedDocs.add(documentModel);
                }
            }
            // add also the unrestricted documents
            for (DocumentModel documentModel : unrestrictedDocs) {
                long modificationTime = 0;
                SynchronizableDocument syncDoc = documentModel.getAdapter(SynchronizableDocument.class);
                tuple = new NuxeoSynchroTuple(documentModel.getId(), documentModel.getId(), syncDoc.getId(),
                        documentModel.getType(), documentModel.getPathAsString(), modificationTime,
                        documentModel.isProxy(), documentModel.isVersion());
                tuple.setContextData(getContextData(documentManager, documentModel, null, null));
                availableTuples.add(tuple);
            }
            // add also the root for user workspaces in case it exists
            if (!domainNames.isEmpty()) {
                UnrestrictedUserWorkspaceReader workspaceReader = new UnrestrictedUserWorkspaceReader(
                        documentManager, domainNames.get(0));
                workspaceReader.runUnrestricted();
                DocumentModel userWorkspaceRoot = workspaceReader.getUserWorkspaceRoot();
                if (userWorkspaceRoot != null) {

                    modificationDate = workspaceReader.getModificationDate();
                    long modificationTime = modificationDate != null ? modificationDate.getTimeInMillis() : 0;
                    SynchronizableDocument syncDoc = userWorkspaceRoot.getAdapter(SynchronizableDocument.class);
                    tuple = new NuxeoSynchroTuple(userWorkspaceRoot.getId(), userWorkspaceRoot.getId(),
                            syncDoc.getId(), userWorkspaceRoot.getType(), userWorkspaceRoot.getPathAsString(),
                            modificationTime, userWorkspaceRoot.isProxy(), userWorkspaceRoot.isVersion());
                    tuple.setContextData(
                            getContextData(documentManager, userWorkspaceRoot, availableDocIds, unrestrictedDocs));
                    availableTuples.add(1, tuple);
                }
            }

        } catch (Exception ce) {
            log.error(ce);
            throw new ClientException(ce);

        } finally {
            if (getSession() != null) {
                // don't forget to close the session
                getSession().logout();
            }
        }
        return availableTuples.toArray(new NuxeoSynchroTuple[0]);
    }

    /**
     * Lists the Nuxeo domain tree filtering the visible to user branches. It includes Comments and Tags. The
     * representation offers enough data to client to decide what more needed for full synchronization.
     *
     * @return
     * @throws ClientException
     */
    @WebMethod(operationName = "getAvailableDocumentList")
    public NuxeoSynchroTuple[] getAvailableDocumentList() throws ClientException {
        return getAvailableDocumentListWithQuery("QUERY_ALL");
    }

    @WebMethod(operationName = "getQueryAvailableDocumentListWithQuery")
    public String getQueryAvailableDocumentListWithQuery(String queryName) throws ClientException {
        String query = getInlinedQuery(queryName);
        if (query == null) {
            query = getQuery(queryName + "_CLIENT_SIDE");
        }
        if (query == null) {
            query = getQuery(queryName);
        }
        return query;
    }

    /**
     * Gets the query used to find all available documents for synchronization
     *
     * @return a string query
     * @throws ClientException
     */
    @WebMethod(operationName = "getQueryAvailableDocumentList")
    public String getQueryAvailableDocumentList() throws ClientException {
        return getQueryAvailableDocumentListWithQuery("QUERY_ALL");
    }

    /**
     * Returns a DocumentSnapshot for a given document id ; this describes a documentModel without blob properties
     *
     * @return DocumentSnapshot
     * @throws ClientException
     */

    @WebMethod(operationName = "getDocumentByIdWithoutBlob")
    public FlagedDocumentSnapshot getDocumentByIdWithoutBlob(String uuid) {
        FlagedDocumentSnapshot ds = null;
        try {
            getSession().login();
            CoreSession documentManager = getSession().getCoreSession();
            DocumentModel documentModel = documentManager.getDocument(new IdRef(uuid));
            ds = new FlagedDocumentSnapshotFactory().newDocumentSnapshot(documentModel);
        } catch (ClientException e) {
            log.error(e);
            DocumentSourceUnrestricted usr = new DocumentSourceUnrestricted(getSession().getCoreSession(),
                    new IdRef(uuid));
            try {
                usr.runUnrestricted();
                ds = usr.documentSnapshot;
            } catch (ClientException e1) {
                log.error(e1);
            }

        } finally {
            getSession().logout();
        }
        return ds;
    }

    public void destroySession() {
        BasicSession session = getSession();
        if (session != null) {
            sessions.remove(session);
            session.disconnect();
        }
    }

    public void keepAlive() {
        // TODO Auto-generated method stub
    }

    private ContextDataInfo[] getContextData(CoreSession documentManager, DocumentModel document,
            List<String> availableDocIds, DocumentModelList unrestrictedDocs) throws Exception {

        List<ContextDataInfo> listContextData = new ArrayList<ContextDataInfo>();
        DocumentModel sourceDocument = null;

        DocumentRef ref = document.getRef();
        // add needed context data
        if (document.isProxy()) {
            DocumentModel version = null;

            String importProxyTargetId = null;

            String importProxyVersionableId = null;

            // first try to get the version from which the proxy was made
            version = documentManager.getSourceDocument(ref);

            if (version != null) {
                importProxyTargetId = version.getId();
                // second try to get the source of the version from which
                // the proxy was made
                if (documentManager.hasPermission(version.getRef(), SecurityConstants.VERSION)) {
                    if (version.getSourceId() != null) {
                        // TODO: importProxyVersionableId =
                        // version.getSourceId()
                        sourceDocument = documentManager.getSourceDocument(version.getRef());
                        if (sourceDocument != null) {
                            importProxyVersionableId = sourceDocument.getId();
                        }
                    }
                } else {
                    log.debug("Current logged user does not have Version security ...");
                    // an restricted user needs to get information about the
                    // proxy sources
                    DocumentSourceUnrestricted usr = new DocumentSourceUnrestricted(documentManager, ref);
                    usr.runUnrestricted();
                    importProxyVersionableId = usr.sourceId;
                }
            }
            if (!availableDocIds.contains(importProxyTargetId)) {
                unrestrictedDocs.add(version);
                availableDocIds.add(importProxyTargetId);
            }
            // add proxy targetId
            listContextData.add(generateDataContextInfo(CoreSession.IMPORT_PROXY_TARGET_ID, importProxyTargetId));
            // add proxy versionable id(source id)
            listContextData.add(
                    generateDataContextInfo(CoreSession.IMPORT_PROXY_VERSIONABLE_ID, importProxyVersionableId));
        } else if (document.isVersion()) {
            String importVersionVersionableId = null;
            List<VersionModel> versions = null;
            String minorVer = null;
            String majorVer = null;
            if (document.getSourceId() == null) {
                // add version description
                listContextData.add(generateDataContextInfo(CoreSession.IMPORT_VERSION_MAJOR, "1"));
                // add version description
                listContextData.add(generateDataContextInfo(CoreSession.IMPORT_VERSION_MINOR, "0"));
                listContextData
                        .add(generateDataContextInfo(CoreSession.IMPORT_VERSION_VERSIONABLE_ID, document.getId()));
                // add version label
                listContextData
                        .add(generateDataContextInfo(CoreSession.IMPORT_VERSION_LABEL, document.getVersionLabel()));
            } else {
                if (documentManager.hasPermission(new IdRef(document.getSourceId()), SecurityConstants.READ)) {
                    sourceDocument = documentManager.getSourceDocument(ref);
                } else {
                    log.debug("Current logged user does not have Version security ...");
                    DocumentSourceUnrestricted usr = new DocumentSourceUnrestricted(documentManager, ref);
                    usr.runUnrestricted();
                    importVersionVersionableId = usr.sourceId;
                    versions = usr.versionsForSourceDocument;
                    minorVer = usr.minorVer;
                    majorVer = usr.majorVer;
                }

                if (importVersionVersionableId == null) {
                    importVersionVersionableId = sourceDocument.getId();
                }
                // add versionable id(source id)
                listContextData.add(generateDataContextInfo(CoreSession.IMPORT_VERSION_VERSIONABLE_ID,
                        importVersionVersionableId));
                // add version label
                listContextData
                        .add(generateDataContextInfo(CoreSession.IMPORT_VERSION_LABEL, document.getVersionLabel()));

                if (versions == null) {
                    versions = documentManager.getVersionsForDocument(sourceDocument.getRef());
                }
                for (VersionModel versionModel : versions) {
                    if (versionModel.getLabel().equals(document.getVersionLabel())) {
                        // add version description
                        listContextData.add(generateDataContextInfo(CoreSession.IMPORT_VERSION_DESCRIPTION,
                                versionModel.getDescription()));
                        // add version creation date
                        listContextData.add(generateDataContextInfo(CoreSession.IMPORT_VERSION_CREATED,
                                new DateType().encode(versionModel.getCreated())));
                        break;
                    }
                }

                if (minorVer == null || majorVer == null) {
                    VersioningDocument docVer = document.getAdapter(VersioningDocument.class);
                    minorVer = docVer.getMinorVersion().toString();
                    majorVer = docVer.getMajorVersion().toString();
                }
                // add version description
                listContextData.add(generateDataContextInfo(CoreSession.IMPORT_VERSION_MAJOR, majorVer));
                // add version description
                listContextData.add(generateDataContextInfo(CoreSession.IMPORT_VERSION_MINOR, minorVer));
            }
        } else {
            // add lock status
            Lock lock = document.getLockInfo();
            if (lock != null) {
                listContextData.add(generateDataContextInfo(CoreSession.IMPORT_LOCK_OWNER, lock.getOwner()));
                String createdString = ISODateTimeFormat.dateTime().print(new DateTime(lock.getCreated()));
                listContextData.add(generateDataContextInfo(CoreSession.IMPORT_LOCK_CREATED, createdString));
            }
            if (document.isVersionable() && documentManager.hasPermission(ref, SecurityConstants.READ)) {
                listContextData
                        .add(generateDataContextInfo(CoreSession.IMPORT_CHECKED_IN, Boolean.FALSE.toString()));
                // add the id of the last version, which represents the base
                // for
                // the current state of the document
                DocumentModel version = documentManager.getLastDocumentVersion(ref);
                if (version != null && version.getId().equals(document.getId())) {
                    listContextData
                            .add(generateDataContextInfo(CoreSession.IMPORT_BASE_VERSION_ID, version.getId()));
                }
                VersioningDocument docVer = document.getAdapter(VersioningDocument.class);
                String minorVer = docVer.getMinorVersion().toString();
                String majorVer = docVer.getMajorVersion().toString();
                // add major version
                listContextData.add(generateDataContextInfo(CoreSession.IMPORT_VERSION_MAJOR, majorVer));
                // add minor version
                listContextData.add(generateDataContextInfo(CoreSession.IMPORT_VERSION_MINOR, minorVer));
            }
        }

        // add current lifecycle state
        listContextData.add(
                generateDataContextInfo(CoreSession.IMPORT_LIFECYCLE_STATE, document.getCurrentLifeCycleState()));
        // add lifecycle policy
        listContextData
                .add(generateDataContextInfo(CoreSession.IMPORT_LIFECYCLE_POLICY, document.getLifeCyclePolicy()));

        return listContextData.toArray(new ContextDataInfo[0]);
    }

    private ContextDataInfo generateDataContextInfo(String dataName, String dataValue) {
        return new ContextDataInfo(dataName, dataValue);
    }

    private String getInlinedQuery(String query) {
        final String upperCase = query.toUpperCase();
        if (upperCase.startsWith("SELECT *")) {
            if (!upperCase.endsWith(" ORDER BY ECM:PATH")) {
                query = query.concat(" ORDER BY ecm:path");
            }
            return query;
        }
        return null;
    }

    private String getQuery(String queryName) throws ClientException {
        PageProviderService ppService = Framework.getLocalService(PageProviderService.class);
        if (ppService == null) {
            throw new ClientException("Unable to get PageProviderService");
        }
        PageProviderDefinition def = ppService.getPageProviderDefinition(queryName);
        if (def != null) {
            return def.getPattern();
        }
        return null;
    }

    /**
     * Helper class to run code with an unrestricted session.The code that will be run, will provide information about
     * the source of a document,usually a version document.
     *
     * @author rux
     */
    protected static class DocumentSourceUnrestricted extends UnrestrictedSessionRunner {

        /**
         * The id of the source document
         */
        public String sourceId;

        /**
         * The ref of the document
         */
        public DocumentRef ref;

        /**
         * The document
         */
        public DocumentModel document;

        /**
         * The source document
         */
        public DocumentModel sourceDocument;

        /**
         * The versions of the source document
         */
        public List<VersionModel> versionsForSourceDocument;

        /**
         * The minor version of the document
         */
        public String minorVer;

        /**
         * The major version of the document
         */
        public String majorVer;

        private FlagedDocumentSnapshot documentSnapshot;

        public DocumentSourceUnrestricted(CoreSession session, DocumentRef ref) {
            super(session);
            this.ref = ref;
        }

        @Override
        public void run() throws ClientException {
            DocumentModel sourceDocument = null;
            try {
                document = session.getDocument(ref);
                // first the source of the version is retrieved
                try {
                    if (document.getSourceId() == null) {
                        throw new ClientException("Document has null source document");
                    }
                    sourceDocument = session.getSourceDocument(ref);
                    if (sourceDocument != null) {
                        sourceId = sourceDocument.getId();
                        this.sourceDocument = sourceDocument;
                        versionsForSourceDocument = session.getVersionsForDocument(sourceDocument.getRef());
                        VersioningDocument docVer = document.getAdapter(VersioningDocument.class);
                        minorVer = docVer.getMinorVersion().toString();
                        majorVer = docVer.getMajorVersion().toString();
                    }
                } catch (ClientException e) {
                    log.error(e.getMessage(), e);
                }
                documentSnapshot = new FlagedDocumentSnapshotFactory().newDocumentSnapshot(document);
            } catch (Exception e) {
                session.cancel();
                log.warn(e);
            }
        }
    }

    protected class UnrestrictedUserWorkspaceReader extends UnrestrictedSessionRunner {

        private DocumentModel userWorkspaceRoot;

        private Calendar modificationDate;

        private final String domainName;

        public UnrestrictedUserWorkspaceReader(CoreSession userCoreSession, String domainName) {
            super(userCoreSession);
            this.domainName = domainName;
        }

        @Override
        public void run() throws ClientException {

            StringBuilder uwsPath = new StringBuilder("/").append(domainName);
            uwsPath.append("/").append("UserWorkspaces");
            PathRef uwsDocRef = new PathRef(uwsPath.toString());
            if (session.exists(uwsDocRef)) {
                userWorkspaceRoot = session.getDocument(uwsDocRef);
                modificationDate = (Calendar) userWorkspaceRoot.getPropertyValue("dc:modified");
            }
        }

        public DocumentModel getUserWorkspaceRoot() {
            return userWorkspaceRoot;
        }

        public Calendar getModificationDate() {
            return modificationDate;
        }
    }

}