001/*
002 * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Thierry Delprat
018 */
019package org.nuxeo.ecm.core.versioning;
020
021import java.util.Collection;
022import java.util.List;
023
024import org.apache.commons.logging.Log;
025import org.apache.commons.logging.LogFactory;
026import org.nuxeo.ecm.core.CoreService;
027import org.nuxeo.ecm.core.api.CoreSession;
028import org.nuxeo.ecm.core.api.DocumentModel;
029import org.nuxeo.ecm.core.api.IdRef;
030import org.nuxeo.ecm.core.event.Event;
031import org.nuxeo.ecm.core.event.EventBundle;
032import org.nuxeo.ecm.core.event.EventContext;
033import org.nuxeo.ecm.core.event.PostCommitEventListener;
034import org.nuxeo.ecm.core.event.impl.ShallowDocumentModel;
035import org.nuxeo.runtime.api.Framework;
036
037/**
038 * Async listener that is in charge to delete the versions. Before running the delete operation on the versions passed
039 * as argument of the event, it will call the registred {@link OrphanVersionRemovalFilter} to allow them to mark some of
040 * the orphan versions to be kept.
041 *
042 * @author <a href="mailto:tdelprat@nuxeo.com">Tiry</a>
043 */
044public class OrphanVersionRemoverListener implements PostCommitEventListener {
045
046    protected static final Log log = LogFactory.getLog(OrphanVersionRemoverListener.class);
047
048    @Override
049    public void handleEvent(EventBundle events) {
050        if (events.containsEventName(DefaultVersionRemovalPolicy.ORPHAN_VERSION_REMOVE)) {
051            for (Event event : events) {
052                if (!event.getName().equals(DefaultVersionRemovalPolicy.ORPHAN_VERSION_REMOVE)) {
053                    continue;
054                }
055                EventContext ctx = event.getContext();
056                CoreSession session = ctx.getCoreSession();
057                Object[] args = ctx.getArguments();
058                if (args.length == 2) {
059                    DocumentModel doc = (DocumentModel) args[0];
060                    ShallowDocumentModel deletedLiveDoc = null;
061                    if (doc instanceof ShallowDocumentModel) {
062                        deletedLiveDoc = (ShallowDocumentModel) doc;
063                    } else {
064                        // cluster node has still no fetched invalidation
065                        // so ShallowDocumentModel has been reconnected via the cache !
066                        deletedLiveDoc = new ShallowDocumentModel(doc);
067                    }
068                    List<String> versionUUIDs = (List<String>) args[1];
069                    removeIfPossible(session, deletedLiveDoc, versionUUIDs);
070                }
071            }
072        }
073    }
074
075    protected Collection<OrphanVersionRemovalFilter> getFilters() {
076        return Framework.getLocalService(CoreService.class).getOrphanVersionRemovalFilters();
077    }
078
079    protected void removeIfPossible(CoreSession session, ShallowDocumentModel deletedLiveDoc, List<String> versionUUIDs)
080            {
081        session.save(); // receive invalidations if no tx
082
083        for (OrphanVersionRemovalFilter filter : getFilters()) {
084            versionUUIDs = filter.getRemovableVersionIds(session, deletedLiveDoc, versionUUIDs);
085            if (versionUUIDs.size() == 0) {
086                break;
087            }
088        }
089
090        for (String id : versionUUIDs) {
091            IdRef idRef = new IdRef(id);
092            if (session.exists(idRef)) {
093                log.debug("Removing version: " + id);
094                session.removeDocument(idRef);
095            }
096        }
097
098        session.save(); // send invalidations if no tx
099    }
100
101}