001/*
002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 *
009 * Contributors:
010 *     Thierry Delprat
011 */
012package org.nuxeo.ecm.core.versioning;
013
014import java.util.Collection;
015import java.util.List;
016
017import org.apache.commons.logging.Log;
018import org.apache.commons.logging.LogFactory;
019import org.nuxeo.ecm.core.CoreService;
020import org.nuxeo.ecm.core.api.CoreSession;
021import org.nuxeo.ecm.core.api.DocumentModel;
022import org.nuxeo.ecm.core.api.IdRef;
023import org.nuxeo.ecm.core.event.Event;
024import org.nuxeo.ecm.core.event.EventBundle;
025import org.nuxeo.ecm.core.event.EventContext;
026import org.nuxeo.ecm.core.event.PostCommitEventListener;
027import org.nuxeo.ecm.core.event.impl.ShallowDocumentModel;
028import org.nuxeo.runtime.api.Framework;
029
030/**
031 * Async listener that is in charge to delete the versions. Before running the delete operation on the versions passed
032 * as argument of the event, it will call the registred {@link OrphanVersionRemovalFilter} to allow them to mark some of
033 * the orphan versions to be kept.
034 *
035 * @author <a href="mailto:tdelprat@nuxeo.com">Tiry</a>
036 */
037public class OrphanVersionRemoverListener implements PostCommitEventListener {
038
039    protected static final Log log = LogFactory.getLog(OrphanVersionRemoverListener.class);
040
041    @Override
042    public void handleEvent(EventBundle events) {
043        if (events.containsEventName(DefaultVersionRemovalPolicy.ORPHAN_VERSION_REMOVE)) {
044            for (Event event : events) {
045                if (!event.getName().equals(DefaultVersionRemovalPolicy.ORPHAN_VERSION_REMOVE)) {
046                    continue;
047                }
048                EventContext ctx = event.getContext();
049                CoreSession session = ctx.getCoreSession();
050                Object[] args = ctx.getArguments();
051                if (args.length == 2) {
052                    DocumentModel doc = (DocumentModel) args[0];
053                    ShallowDocumentModel deletedLiveDoc = null;
054                    if (doc instanceof ShallowDocumentModel) {
055                        deletedLiveDoc = (ShallowDocumentModel) doc;
056                    } else {
057                        // cluster node has still no fetched invalidation
058                        // so ShallowDocumentModel has been reconnected via the cache !
059                        deletedLiveDoc = new ShallowDocumentModel(doc);
060                    }
061                    List<String> versionUUIDs = (List<String>) args[1];
062                    removeIfPossible(session, deletedLiveDoc, versionUUIDs);
063                }
064            }
065        }
066    }
067
068    protected Collection<OrphanVersionRemovalFilter> getFilters() {
069        return Framework.getLocalService(CoreService.class).getOrphanVersionRemovalFilters();
070    }
071
072    protected void removeIfPossible(CoreSession session, ShallowDocumentModel deletedLiveDoc, List<String> versionUUIDs)
073            {
074        session.save(); // receive invalidations if no tx
075
076        for (OrphanVersionRemovalFilter filter : getFilters()) {
077            versionUUIDs = filter.getRemovableVersionIds(session, deletedLiveDoc, versionUUIDs);
078            if (versionUUIDs.size() == 0) {
079                break;
080            }
081        }
082
083        for (String id : versionUUIDs) {
084            IdRef idRef = new IdRef(id);
085            if (session.exists(idRef)) {
086                log.debug("Removing version: " + id);
087                session.removeDocument(idRef);
088            }
089        }
090
091        session.save(); // send invalidations if no tx
092    }
093
094}