All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.openwfe.org.engine.expressions.ParticipantExpression Maven / Gradle / Ivy

There is a newer version: 1.7.2
Show newest version
/*
 * Copyright (c) 2001-2006, John Mettraux, OpenWFE.org
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met:
 * 
 * . Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.  
 * 
 * . Redistributions in binary form must reproduce the above copyright notice, 
 *   this list of conditions and the following disclaimer in the documentation 
 *   and/or other materials provided with the distribution.
 * 
 * . Neither the name of the "OpenWFE" nor the names of its contributors may be
 *   used to endorse or promote products derived from this software without
 *   specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id: ParticipantExpression.java 2718 2006-06-02 05:24:52Z jmettraux $
 */

//
// ParticipantExpression.java
//
// [email protected]
//
// generated with 
// jtmpl 1.0.04 20.11.2001 John Mettraux ([email protected])
//

package openwfe.org.engine.expressions;

import openwfe.org.time.Time;
import openwfe.org.engine.Definitions;
import openwfe.org.engine.expool.ExpressionPool;
import openwfe.org.engine.history.History;
import openwfe.org.engine.workitem.Attribute;
import openwfe.org.engine.workitem.BooleanAttribute;
import openwfe.org.engine.workitem.CancelItem;
import openwfe.org.engine.workitem.HistoryItem;
import openwfe.org.engine.workitem.InFlowWorkItem;
import openwfe.org.engine.dispatch.DispatchingException;
import openwfe.org.engine.expressions.state.FrozenState;
import openwfe.org.engine.participants.Filter;
import openwfe.org.engine.participants.Participant;
import openwfe.org.engine.participants.ParticipantMap;


/**
 * A leaf (terminal) expression : a reference to a participant.
 * 

This expression now includes the 'dyna-participant' functionality

* *

CVS Info : *
$Author: jmettraux $ *
$Date: 2006-06-02 07:24:52 +0200 (Fri, 02 Jun 2006) $ *
$Id: ParticipantExpression.java 2718 2006-06-02 05:24:52Z jmettraux $
* * @author [email protected] */ public class ParticipantExpression extends ZeroChildExpression implements ExpressionWithTimeOut { private final static org.apache.log4j.Logger log = org.apache.log4j.Logger .getLogger(ParticipantExpression.class.getName()); // // CONSTANTS /** * The attribute 'ref' indicates to this expression which is the participant * that should receive the workitem. * See also 'default-ref', 'field-ref', 'variable-ref' and 'else-ref'. */ public final static String A_REF = "ref"; /** * Use this attribute 'filter' to link this participant expression to a * filter. */ public final static String A_FILTER = "filter"; private final static String HISTORY_TEXT = "ok"; /** * In the flow definition, use this attribute of 'participant' to * determine the value of the '__description__' field. */ public final static String A_DESCRIPTION = "description"; /** * States the name of the field that will be added (and later removed) to * the workitem if the description attribute is present. */ public final static String DESCRIPTION_FIELD_NAME = "__description__"; /** * use this parameter name to set the default participant who * will receive the workitem if no participant is indicated * in the workitem */ public final static String A_DEFAULT_REF = "default-ref"; /** * use this parameter name to tell the expression in which field of * the incoming workitem the target participant name will be found */ public final static String A_FIELD_REF = "field-ref"; /** * use this param name to indicate to the engine in which variable it * shall find the name of the participant to which it should dispatch the * workitem. */ public final static String A_VARIABLE_REF = "variable-ref"; /** * When 'field-ref' is not set, the target participant is to be found * in the '__next_participant__' field of the workitem. (And of course, * if it is not set, default-ref, will be consulted) */ public final static String DEFAULT_FIELD_REF = "__next_participant__"; /** * This 'else-ref' attribute accepts a comma separated list of successful * 'failover participant', ie participants that will receive the workitem * if delivery failed to the regularly referenced participant ('ref'). * Each participant in this else list will get probed until dispatching * is successful.
* If none of them is available, the participant expression will get frozen. */ public final static String A_ELSE_REF = "else-ref"; /** * If the attribute 'forget' is set to 'true', the participant expression * will just take care of dispatching the workitem to the participant. * It will not wait for the reply and will immediately hand the flow * back to its parent expression. */ public final static String A_FORGET = "forget"; /** * If the dispatched workitem is to be forgotten by the engine, a field * named '__forgotten__' will be set to true in it, so that the * target could lookup this field and know the situation. */ public final static String F_FORGOTTEN_FIELD = "__forgotten__"; // // FIELDS private Filter filter = null; /* * * If this participant has a filter, at dispatch time, the workitem * is stored in this field (and the expression state is stored again * in the expression pool via 'storeItself') */ private InFlowWorkItem appliedWorkitem = null; /** * If this value is defined, each time this expression is applied a field * named '__description__' will be set in the workitem dispatched to the * participant. * When the participant will reply, the field will be unset. */ protected String description = null; /** * When setting the description field, this expression will * keep track of the old value and set back when the participant replies. */ protected Attribute oldDescriptionValue = null; protected String dynaParticipantName = null; // it is determined once and only once, after it is // kept, even when the expression gets stored // // CONSTRUCTORS // // BEAN METHODS public Filter getFilter () { return this.filter; } public InFlowWorkItem getAppliedWorkitem () { return this.appliedWorkitem; } public void setFilter (Filter f) { this.filter = f; } public void setAppliedWorkitem (InFlowWorkItem wi) { this.appliedWorkitem = wi; } // // METHODS /* * debug override */ public void setParent (final FlowExpressionId fei) { //log.debug("setParent() \n for "+this.getId()+"\n to "+fei); //openwfe.org.Utils.logStackTrace(log, "setParent()"); super.setParent(fei); } /** * Extracts the name of the participants who should receive the workitem * (it looks in the expression and if necessary in the workitem). */ protected String getParticipantName (final InFlowWorkItem wi) throws ApplyException { if (this.dynaParticipantName != null) // // alreay determined // return this.dynaParticipantName; //log.debug("getParticipantName() name has to be determined"); // // determine key for looking up participant String defaultParticipantName = lookupAttribute(A_DEFAULT_REF, wi); String ref = lookupAttribute(A_REF, wi); String fieldRef = lookupAttribute(A_FIELD_REF, wi); String variableRef = lookupAttribute(A_VARIABLE_REF, wi); if (fieldRef == null && variableRef == null) fieldRef = DEFAULT_FIELD_REF; // // lookup name of 'real participant' Object participantName = null; if (ref != null) participantName = ref; else if (fieldRef != null && this.appliedWorkitem != null) participantName = this.appliedWorkitem.getAttribute(fieldRef); else if (variableRef != null) participantName = lookupVariable(variableRef); if (participantName == null) this.dynaParticipantName = defaultParticipantName; else this.dynaParticipantName = participantName.toString(); if (this.dynaParticipantName == null) this.dynaParticipantName = lookupAttribute(A_REF, wi); if (this.dynaParticipantName == null) { throw new ApplyException ("Could not determine dynamically or statically the target "+ "participant. Is '"+A_FIELD_REF+ "', '"+A_VARIABLE_REF+"' or '"+A_REF+ "' set in the flow definition ?"); } //log.debug // ("getParticipantName() result : >"+this.dynaParticipantName+"<"); return this.dynaParticipantName; } /** * Retrieves the participant associated with this participant */ protected Participant lookupParticipant (final InFlowWorkItem wi) throws ApplyException { //log.debug("this.attributes = "+this.attributes); String participantName = getParticipantName(wi); //log.debug("this.applicationContext = "+this.applicationContext); final ParticipantMap pMap = Definitions.getParticipantMap(context()); if (pMap == null) { throw new ApplyException ("Cannot find participantMap service. "+ "Cannot retrieve any participant."); } final Participant result = pMap.get(participantName); if (result == null) { throw new ApplyException ("Participant '"+participantName+"' not found"); } wi.setParticipantName(participantName); return result; } /** * Applies this expression, ie dispatches the workitem to the * participant according to the participant map * (etc-engine/participants.xml) */ public void apply (final InFlowWorkItem wi) throws ApplyException { touchApplyTime(); ValueUtils.cleanResult(wi); // so that participants do not see any '__result__' field // // should forget ? final String s = lookupAttribute(A_FORGET, wi); final boolean shouldForget = (s != null && s.trim().equals("true")); // // determine filter and description now if (this.getAttributes().keySet().contains(A_FILTER)) { final String filterName = lookupAttribute(A_FILTER, wi); final FilterDefinitionExpression fde = (FilterDefinitionExpression)this.lookupVariable(filterName); if (fde != null) { fde.setApplicationContext(this.context()); // making sure it has a context this.filter = fde.buildFilter(wi); } else { log.warn("apply() did not find filter '"+filterName+"'"); } } this.description = lookupAttribute(A_DESCRIPTION, wi); //log.debug("apply() description is \""+this.description+"\""); // // do the job... this.tag(wi); this.appliedWorkitem = (InFlowWorkItem)wi.clone(); // // should we set a description field ? if (this.description != null) { this.oldDescriptionValue = wi .getAttribute(DESCRIPTION_FIELD_NAME); wi.getAttributes().puts(DESCRIPTION_FIELD_NAME, this.description); } // // apply filter if any InFlowWorkItem itemToDispatch = wi; if (this.filter != null) itemToDispatch = this.filter.constrain(wi); if (shouldForget) itemToDispatch.getAttributes().puts(F_FORGOTTEN_FIELD, "true"); // // store itself in the expression to keep track of apply time and // other such fields storeItself(); // // dispatch regularDispatch(itemToDispatch); // // forget ? if (shouldForget) { if (log.isDebugEnabled()) log.debug("apply() forget is set to 'true', resuming flow"); try { wi.getAttributes().remove(F_FORGOTTEN_FIELD); this.reply(wi); } catch (final ReplyException e) { throw new ApplyException ("participant with forget set to 'true' : "+ "failed to immediately reply to parent"); } } } /** * Does the job of regular (not 'else-ref' based dispatching). */ protected void dispatch (final Participant participant, final String participantName, final InFlowWorkItem wi) throws ApplyException, DispatchingException { // identify participant name wi.setParticipantName(participantName); // dispatch participant.dispatch(context(), wi); } /** * Initiates the dispatching mechanism. */ protected void regularDispatch (final InFlowWorkItem wi) { String pName = null; try { final Participant p = lookupParticipant(wi); pName = getParticipantName(wi); dispatch(p, pName, wi); this.historyLog (wi, History.EVT_DISPATCH, pName, this.getClass().getName()); return; } catch (final Throwable t) { if (log.isDebugEnabled()) { log.debug ("regularDispatch() failed to dispatch to '"+ pName+"'", t); } log.warn ("regularDispatch() failed to dispatch to '"+ pName+"'\n"+t); this.historyLog (wi, History.EVT_DISPATCH_FAILURE, pName, ""+t); } elseDispatch(wi); } /** * Is called by regularDispatch() in case of failure. Freezes the * expression if it itself fails. */ protected void elseDispatch (final InFlowWorkItem wi) { final String sElseList = lookupAttribute(A_ELSE_REF, wi); if (sElseList != null) { String[] ss = sElseList.split(","); for (int i=0; i "+getId()); if (this.appliedWorkitem == null) // // no need to send a cancel item, the expression was not applied // return null; final Participant participant = lookupParticipant(this.appliedWorkitem); final CancelItem ci = new CancelItem (getId(), getParticipantName(this.appliedWorkitem)); try { participant.dispatch(context(), ci); if (log.isDebugEnabled()) log.debug("cancel() cancelItem dispatched"); } catch (DispatchingException de) { throw new ApplyException ("Failed to notify participant '"+ getParticipantName(this.appliedWorkitem)+ "' with cancel item", de); } super.cancel(); return this.appliedWorkitem; } /* * cloning the filter is not necessary so this method override * is not necessary anymore. * public Object clone () { final ParticipantExpression clone = (ParticipantExpression)super.clone(); clone.setFilter(getFilter()); return clone; } */ // // METHODS from ExpressionWithTimeOut /** * This method should return false if the purge daemon should not * consider the implemented and instantiated Expression during its run. */ public boolean isTimeOutActivated () { if (getApplyTime() == null || (this.getState() instanceof FrozenState)) { return false; } return (determineTimeOut().longValue() != -1); } /** * This method is called by the ExpressionStore when it notices that the * ParticipantExpression expired. */ public void timeOutReply () throws ReplyException { // // tagging the workitem with timeout history... String participantName = "unknown"; try { participantName = getParticipantName(this.appliedWorkitem); } catch (final ApplyException e) { // leave to 'unknown' } this.appliedWorkitem.addHistoryItem (participantName, "participant timed out"); // // log timeout in history historyLog (this.appliedWorkitem, EVT_TIMED_OUT, participantName, ""); if (log.isDebugEnabled()) { log.debug ("timeOutReply() "+ "setting '"+Definitions.V_TIMED_OUT+"' to 'true'"); } //getExpressionPool().setVariableInParent // (this, Definitions.V_TIMED_OUT, Boolean.TRUE); this.appliedWorkitem.getAttributes() .put(Definitions.V_TIMED_OUT, new BooleanAttribute(true)); if (log.isDebugEnabled()) log.debug("timeOutReply() cancelling self..."); try { this.cancel(); } catch (ApplyException ae) { if (log.isDebugEnabled()) log.debug("Failed to send cancel message", ae); throw new ReplyException ("Failed to send cancel message", ae); } // // resume flow if (log.isDebugEnabled()) log.debug("timeOutReply() resuming flow"); super.reply(this.appliedWorkitem); } /** * By implementing this method, expressions define how their * timeout is determined. * The priority list for setting the timeout of a * participant expression is :
*

    *
  1. expression's 'timeout' attribute
  2. *
  3. expression's variable scope ('__timeout__')
  4. *
  5. participant's timeout parameter * (as found in the participant map)
  6. *
  7. expressionPool's 'expressionTimeout' parameter (default)
  8. *
*/ public Long determineTimeOut () { Long timeOut = TimeoutUtils .determineTimeout(this, this.appliedWorkitem); if (timeOut == null) // // determine time out at participant level { Participant participant = null; try { participant = this.lookupParticipant(this.appliedWorkitem); } catch (final ApplyException ae) { log.info ("determineTimeOut() "+ "Couldn't determine participant for timeout computation", ae); } if (participant != null) { String sTimeOut = null; if (participant.getParams() != null) sTimeOut = (String)participant.getParams().get(TIMEOUT); //if (sTimeOut != null) timeOut = TimeoutUtils.determineTimeout(sTimeOut); } } // // determine timeOut at engine (expressionPool) level // (lowest priority) if (timeOut == null) timeOut = getExpressionPool().getExpressionTimeOut(); // NB : returning a timeout of "-1" means timeout is deactivated // for the participant if (timeOut == null) timeOut = new Long(-1); // // this transformation shouldn't be necessary if (log.isDebugEnabled()) { if (timeOut.longValue() > -1) { log.debug ("determineTimeOut() "+ "time out for participant is set to "+timeOut.longValue()+ " ("+Time.toTimeString(timeOut, false)+")."); } else { log.debug ("determineTimeOut() no time out for participant."); } } return timeOut; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy