/*
* eXist Open Source Native XML Database
* Copyright (C) 2006-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 org.exist.xmldb.XmldbURI;
import org.exist.storage.txn.Txn;
/** Finite State Machine, managing the state of a Running trigger;
* allows to avoid infinite recursions by forbidding another trigger to run
* where there is already one; feature trigger_update .
* I implemented that when a trigger is running , another trigger in the same
* Thread cannot be fired .
* There is a second condition that when a trigger is running triggered by
* some document d, even the same trigger cannot run on a different document .
* maybe TODO: apply "state" design pattern */
public class TriggerStatePerThread {
public static final int NO_TRIGGER_RUNNING = (0);
public static final int TRIGGER_RUNNING_PREPARE = (1);
public static final int TRIGGER_RUNNING_FINISH = (2);
private static ThreadLocal<TriggerState> triggerRunningState = new ThreadLocal<TriggerState>() {
protected synchronized TriggerState initialValue() {
return new TriggerState(NO_TRIGGER_RUNNING);
}
};
/** */
public static boolean verifyUniqueTriggerPerThreadBeforePrepare(
DocumentTrigger trigger, XmldbURI modifiedDocument) {
if (getTriggerRunningState() == NO_TRIGGER_RUNNING) {
setTriggerRunningState(TRIGGER_RUNNING_PREPARE, trigger,
modifiedDocument);
return true;
} else {
return false;
}
}
/**
* @param modifiedDocument
* the document whose modification triggered the trigger
*/
public static boolean verifyUniqueTriggerPerThreadBeforeFinish(
DocumentTrigger trigger, XmldbURI modifiedDocument) {
// another trigger is already running
final DocumentTrigger runningTrigger = getRunningTrigger();
if ( runningTrigger != null &&
trigger != runningTrigger ) {
return false;
}
// current trigger is busy with another document
if(getModifiedDocument() != null && !modifiedDocument.equals(getModifiedDocument()))
{
return false;
}
if (getTriggerRunningState() == TRIGGER_RUNNING_PREPARE) {
setTriggerRunningState(TRIGGER_RUNNING_FINISH, trigger,
modifiedDocument);
return true;
} else {
return false;
}
}
public static class TriggerState {
private int state;
private DocumentTrigger currentTrigger;
private Txn txn;
private XmldbURI modifiedDocument;
public TriggerState(int state) {
super();
this.setState(state, null, null);
}
private void setState(int state, DocumentTrigger trigger, XmldbURI modifiedDocument) {
this.state = state;
if (state == NO_TRIGGER_RUNNING) {
this.currentTrigger = null;
this.setModifiedDocument(null);
} else {
this.currentTrigger = trigger;
this.setModifiedDocument(modifiedDocument);
}
}
private int getState() {
return state;
}
void setTransaction(Txn txn) {
this.txn = txn;
}
Txn getTransaction() {
return txn;
}
public DocumentTrigger getTrigger() {
return currentTrigger;
}
private void setModifiedDocument(XmldbURI modifiedDocument) {
this.modifiedDocument = modifiedDocument;
}
private XmldbURI getModifiedDocument() {
return modifiedDocument;
}
}
public static int getTriggerRunningState() {
return triggerRunningState.get().getState();
}
public static DocumentTrigger getRunningTrigger() {
return triggerRunningState.get().getTrigger();
}
public static void setTriggerRunningState( int state, DocumentTrigger trigger, XmldbURI modifiedDocument ) {
triggerRunningState.get().setState(state, trigger, modifiedDocument);
}
public static Txn getTransaction() {
return triggerRunningState.get().getTransaction();
}
public static void setTransaction(Txn txn) {
triggerRunningState.get().setTransaction(txn);
}
public static XmldbURI getModifiedDocument() {
return triggerRunningState.get().getModifiedDocument();
}
}