/* * eXist Open Source Native XML Database * Copyright (C) 2004-2012 The eXist Project * http://exist-db.org * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * $Id$ */ package org.exist.collections.triggers; import java.io.IOException; import java.net.URISyntaxException; import java.util.Date; import java.util.List; import java.util.Map; import org.exist.EXistException; import org.exist.collections.Collection; import org.exist.dom.persistent.DocumentImpl; import org.exist.security.PermissionDeniedException; import org.exist.storage.DBBroker; import org.exist.storage.txn.Txn; import org.exist.util.LockException; import org.exist.xmldb.XmldbURI; import org.exist.xquery.XPathException; import org.exist.xquery.value.DateTimeValue; /** * This collection trigger will save all old versions of documents before * they are overwritten or removed. The old versions are kept in the * 'history root' which is by default '<code>/db/history</code>', but can be * changed with the parameter '<code>root</code>'. * You need to configure this trigger for every collection whose history you * want to preserve, by modifying '<code>collection.xconf</code>' such that it * resembles this: * * <pre> * <?xml version='1.0'?> * <collection xmlns='http://exist-db.org/collection-config/1.0'> * <triggers> * <trigger * event='update' * class='org.exist.collections.triggers.HistoryTrigger' * /> * <trigger * event='remove' * class='org.exist.collections.triggers.HistoryTrigger' * /> * </triggers> * </collection> * </pre> * * @author Mark Spanbroek * @see org.exist.collections.triggers.Trigger */ public class HistoryTrigger extends FilteringTrigger implements DocumentTrigger { protected XmldbURI rootPath = XmldbURI.ROOT_COLLECTION_URI.append("history"); public void configure(DBBroker broker, Collection parent, Map<String, List<?>> parameters) throws TriggerException { super.configure(broker, parent, parameters); if(parameters.containsKey("root")) { try { rootPath = XmldbURI.xmldbUriFor(parameters.get("root").get(0).toString()); } catch(final URISyntaxException e) { throw new TriggerException(e); } } } public void makeCopy(DBBroker broker, Txn txn, DocumentImpl doc) throws TriggerException { if (doc == null) {return;} // construct the destination path final XmldbURI path = rootPath.append(doc.getURI()); try { //construct the destination document name String dtValue = new DateTimeValue(new Date(doc.getMetadata() .getLastModified())).getStringValue(); dtValue = dtValue.replaceAll(":", "-"); // multiple ':' are not allowed in URI so use '-' dtValue = dtValue.replaceAll("\\.", "-"); // as we are using '-' instead of ':' do the same for '.' final XmldbURI name = XmldbURI.create(dtValue); // create the destination document //TODO : how is the transaction handled ? It holds the locks ! final Collection destination = broker.getOrCreateCollection(txn, path); broker.saveCollection(txn, destination); broker.copyResource(txn, doc, destination, name); } catch(final XPathException xpe) { throw new TriggerException(xpe); } catch(final IOException exception) { throw new TriggerException(exception); } catch(final PermissionDeniedException exception) { throw new TriggerException(exception); } catch(final LockException exception) { throw new TriggerException(exception); } catch (final EXistException exception) { throw new TriggerException(exception); } } @Override public void beforeCreateDocument(DBBroker broker, Txn txn, XmldbURI uri) throws TriggerException { //Nothing to do } @Override public void afterCreateDocument(DBBroker broker, Txn txn, DocumentImpl document) throws TriggerException { //Nothing to do } @Override public void beforeUpdateDocument(DBBroker broker, Txn txn, DocumentImpl document) throws TriggerException { makeCopy(broker, txn, document); } @Override public void afterUpdateDocument(DBBroker broker, Txn txn, DocumentImpl document) throws TriggerException { //Nothing to do } @Override public void beforeCopyDocument(DBBroker broker, Txn txn, DocumentImpl document, XmldbURI newUri) throws TriggerException { makeCopy(broker, txn, document); } @Override public void afterCopyDocument(DBBroker broker, Txn txn, DocumentImpl document, XmldbURI newUri) throws TriggerException { //Nothing to do } @Override public void beforeDeleteDocument(DBBroker broker, Txn txn, DocumentImpl document) throws TriggerException { makeCopy(broker, txn, document); } @Override public void beforeMoveDocument(DBBroker broker, Txn txn, DocumentImpl document, XmldbURI newUri) throws TriggerException { makeCopy(broker, txn, document); } @Override public void afterMoveDocument(DBBroker broker, Txn txn, DocumentImpl document, XmldbURI newUri) throws TriggerException { //Nothing to do } @Override public void afterDeleteDocument(DBBroker broker, Txn txn, XmldbURI uri) throws TriggerException { //Nothing to do } @Override public void beforeUpdateDocumentMetadata(DBBroker broker, Txn txn, DocumentImpl document) throws TriggerException { //Nothing to do } @Override public void afterUpdateDocumentMetadata(DBBroker broker, Txn txn, DocumentImpl document) throws TriggerException { //Nothing to do } }