001/*
002 * (C) Copyright 2006-2008 Nuxeo SAS (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Alexandre Russel
016 *
017 * $Id$
018 */
019
020package org.nuxeo.ecm.platform.annotations.repository.service;
021
022import org.apache.commons.logging.Log;
023import org.apache.commons.logging.LogFactory;
024import org.nuxeo.ecm.core.api.DocumentModel;
025import org.nuxeo.ecm.core.api.DocumentRef;
026import org.nuxeo.ecm.core.api.NuxeoPrincipal;
027import org.nuxeo.ecm.core.api.event.DocumentEventTypes;
028import org.nuxeo.ecm.core.api.facet.VersioningDocument;
029import org.nuxeo.ecm.core.event.Event;
030import org.nuxeo.ecm.core.event.EventContext;
031import org.nuxeo.ecm.platform.annotations.api.Annotation;
032import org.nuxeo.ecm.platform.annotations.api.AnnotationsConstants;
033import org.nuxeo.ecm.platform.annotations.api.AnnotationsService;
034import org.nuxeo.ecm.platform.annotations.repository.URNDocumentViewTranslator;
035import org.nuxeo.ecm.platform.relations.api.Graph;
036import org.nuxeo.ecm.platform.relations.api.Resource;
037import org.nuxeo.ecm.platform.relations.api.Statement;
038import org.nuxeo.ecm.platform.relations.api.impl.ResourceImpl;
039import org.nuxeo.ecm.platform.relations.api.impl.StatementImpl;
040import org.nuxeo.runtime.api.Framework;
041
042import java.net.URI;
043import java.security.Principal;
044import java.util.ArrayList;
045import java.util.List;
046
047/**
048 * @author <a href="mailto:arussel@nuxeo.com">Alexandre Russel</a>
049 */
050public class DocumentVersionnedGraphManager implements GraphManagerEventListener {
051
052    private static final Log log = LogFactory.getLog(DocumentVersionnedGraphManager.class);
053
054    private URNDocumentViewTranslator translator;
055
056    @Override
057    public void manage(Event event) {
058        if (translator == null) {
059            translator = new URNDocumentViewTranslator();
060        }
061        EventContext context = event.getContext();
062        NuxeoPrincipal user = null;
063        Principal principal = context.getPrincipal();
064        if (principal instanceof NuxeoPrincipal) {
065            user = (NuxeoPrincipal) principal;
066        } else {
067            log.debug("Discading event on a non NuxeoPrincipal user");
068            return;
069        }
070
071        DocumentModel docModel = (DocumentModel) context.getArguments()[0];
072        String docId = docModel.getId();
073        String repo = docModel.getRepositoryName();
074
075        if (DocumentEventTypes.DOCUMENT_CHECKEDIN.equals(event.getName())) {
076            DocumentRef versionRef = (DocumentRef) context.getProperty("checkedInVersionRef");
077            copyGraphFor(repo, docId, versionRef.toString(), user);
078        } else if (DocumentEventTypes.DOCUMENT_REMOVED.equals(event.getName())
079                || DocumentEventTypes.VERSION_REMOVED.equals(event.getName())) {
080            removeGraphFor(repo, docId, user);
081        } else if (DocumentEventTypes.DOCUMENT_RESTORED.equals(event.getName())) {
082            String versionUUID = (String) context.getProperty(VersioningDocument.RESTORED_VERSION_UUID_KEY);
083            restoreGraphFor(repo, versionUUID, docId, user);
084        }
085    }
086
087    private void copyGraphFor(String repositoryName, String fromId, String toId, NuxeoPrincipal principal) {
088        copyGraphFor(translator.getNuxeoUrn(repositoryName, fromId), translator.getNuxeoUrn(repositoryName, toId),
089                principal);
090    }
091
092    private static void copyGraphFor(URI current, URI copied, NuxeoPrincipal user) {
093        List<Statement> newStatements = new ArrayList<Statement>();
094        AnnotationsService service = Framework.getService(AnnotationsService.class);
095        List<Annotation> annotations = service.queryAnnotations(current, user);
096        log.debug("Copying annotations graph from " + current + " to " + copied + " for " + annotations.size()
097                + " annotations.");
098        for (Annotation annotation : annotations) {
099            List<Statement> statements = annotation.getStatements();
100            for (Statement statement : statements) {
101                if (statement.getPredicate().equals(AnnotationsConstants.a_annotates)) {
102                    Resource resource = (Resource) statement.getObject();
103                    if (current.toString().equals(resource.getUri())) {
104                        // copy only the statements associated to the current
105                        // URI
106                        Statement newStatement = new StatementImpl(statement.getSubject(), statement.getPredicate(),
107                                new ResourceImpl(copied.toString()));
108                        newStatements.add(newStatement);
109                    }
110                }
111            }
112        }
113        Graph graph = service.getAnnotationGraph();
114        graph.add(newStatements);
115    }
116
117    private void removeGraphFor(String repositoryName, String id, NuxeoPrincipal principal) {
118        removeGraphFor(translator.getNuxeoUrn(repositoryName, id), principal);
119    }
120
121    private static void removeGraphFor(URI uri, NuxeoPrincipal user) {
122        log.debug("Removing annotations graph for " + uri);
123        AnnotationsService service = Framework.getService(AnnotationsService.class);
124        List<Annotation> annotations = service.queryAnnotations(uri, user);
125        for (Annotation annotation : annotations) {
126            service.deleteAnnotationFor(uri, annotation, user);
127        }
128    }
129
130    private void restoreGraphFor(String repositoryName, String versionId, String docId, NuxeoPrincipal principal) {
131        log.debug("Restoring annotations graph for docId:" + docId + " and versionId:" + versionId);
132        removeGraphFor(translator.getNuxeoUrn(repositoryName, docId), principal);
133        copyGraphFor(repositoryName, versionId, docId, principal);
134    }
135
136}