/* ======================================================================= *
* .:;tjfLLffji, *
* :,itLDKW#########Kj, *
* .:ijLGEW########KEEKKW###Kf, *
* .,ifLGEK###########KDLfjjjffGE###Ei *
* .:,;tLDEW#######WKEDGLfLK##KLjjjjjjjjjjjE###Wt *
* :;jLDEK#######WKEDGLffjjjjjD###DjjjjjjjjjjjjLW###L. *
* .;jGK#########WDGLffjjjjjjjjjjjD###DjjjjjjjjjjjjLW###G: *
* GW###WKDDDDEK#####KDLjjjjjjjjjjjfK##WGfjjjjjjjjjjK###Ei *
* i###WDLfjjjjjfLKW#####EGLfjjjjjjjjLK##WEGfjjjjjfLD###Kt. *
* ;E##KLjjjjjjjjjjjfGEW#####KEGfjjjjjjfW####WEDDEEK###WG; *
* f##WLjjjjjjjjjjjjjjjfLDW#####WGfjjjjjGW############Gi. *
* .f##KLjjjjjjjjjjjjjjjjjjjfLDEW####WW########KGLft;,. *
* iK##EfjjjjjjjjjjjjjjjjjjjjjjfGK#######WGjt;: *
* .j###KGfjjjjjjjjjjjjjjjjjjjjjjfLDKW###WELt, *
* jE#####DLfjjjjjjjjjjjjjjjjjjjjjjjfLEW#####Gj,. *
* ,jGK####KEGfjjjjjjjjjjjjjjjjjjjjjjjfGEK####WDj; *
* ,tLW####WKLfjjjjjjjjjjjjjjjjjjjjjjjfLDW####WL *
* ;jGK####KEGfjjjjjjjjjjjjjjjjjjjjjjjfGEW###i *
* .,;itLDEK#########WGLfjjjjjjjjjjjjjjjjjjjjjfD##Wt *
* ,fGEKW#######WWEEEW#####KDLfjjjjjjjjjjjjjjjjjjjfK##G: *
* .iGK############ELjjjfGDK#####KEfjjjjjjjjjjjjjjjjjfE##G: *
* .fW###EGLffjfLDK####LjjjjjjfLDKW####WEGLfjjjjjjjjjjLK##Ki *
* .jW###EjjjjjjjjjfGW##KfjjjjjjjjjfGE######KGfjjjjjfLDW###t. *
* ;E###EfjjjjjjjjjjjGW##DjjjjjjjjjjjjLDKW####WEEEEEK####WG *
* tW###DjjjjjjjjjjjjfK##KfjjjjjjjjjjjjjfGE############KGi. *
* ;E###EfjjjjjjjjjjjGW##DjjjjfLGDEEKW########KEGLfj,. *
* .jW###EjjjjjjjjjfDW##WDGEEKK#######WKEDLfj;,. *
* .jK###EGffjjfLDK############WEDGLj;,:. *
* .;LK#############WDLft;,: *
* ,fGEKKKKEGfjt;,. *
* ,jjjji, *
* *
* Shocks Servlet Framework� *
* Copyright (c) 2003, NRFX Technologies LLC (www.nrfx.com) *
* All Rights Reserved. *
* *
* Licensed under the Academic Free License version 2.0; you may not use *
* this file except in compliance with the License. You may obtain a *
* copy of the License at http://www.opensource.org/licenses/afl-2.0.php *
* *
* Software distributed under the License is distributed on an "AS IS" *
* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express *
* or implied. See the License for the specific language governing *
* permissions and limitations under the License. *
* ======================================================================= */
package shocks.framework.workflow.filter.repository;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletContext;
import shocks.client.*;
import shocks.dawp.Action;
import shocks.dawp.DataSource;
import shocks.dawp.Workflow;
import org.apache.log4j.*;
/**
* <p>Filters are <code>Workflow</code> components dynamically generated
* according to the specifications in the workflow descriptor file. The
* Filter object itself provides an abstract framework for the execution
* of actions created by the developer.</p>
*
* <p>Filters can be assigned <code>Action</code> components at the time
* they are constructed. Examples of these action components are classes
* which extend the <code>ActionSupport</code> and <code>FilterSupport</code>
* objects.</p>
*
* <p>Each filter can perform actions at two points. The first point is
* on the way into the sequence of filters (when the flow of control is
* moving in the direction of the target <code>Action</code>). The second
* point is after the target <code>Action</code> has executed and the flow of
* control is moving back toward the <code>WorkflowController</code>.</p>
*
* <p>Because <code>Filter</code> objects do not contain any business logic
* (only logic which controls the order in which business logic is executed),
* they rely on feedback from the actions to determine what happens next.</p>
*
*/
public class Filter implements Workflow, Cloneable {
private FilterSupport incoming = null;
private FilterSupport outgoing = null;
private Workflow nextFilter = null;
private DataSource metadata;
/**
* Name of the filter, taken from the workflow metadata.
*/
public final String NAME;
/**
* Current version of the filter, taken from the workflow metadata.
*/
public final String VERSION;
/**
* Name of the incoming action, which must be a valid
* <code>FilterSupport</code> class.
*/
public final String INCOMING;
/**
* Name of the outgoing action, which must be a valid
* <code>FilterSupport</code> class.
*/
public final String OUTGOING;
private boolean initialized = false;
private Logger log = Logger.getLogger("Shocks][Filter");
public Filter(DataSource metadata, Action incoming, Action outgoing) {
NAME = ((String)metadata.getAttribute("name"));
VERSION = ((String)metadata.getAttribute("version"));
INCOMING = ((String)metadata.getAttribute("incoming"));
OUTGOING = ((String)metadata.getAttribute("outgoing"));
this.metadata = metadata;
if(incoming == null) {
throw new Error("incoming action was null for " + NAME + " filter.");
} else {
this.incoming = (FilterSupport)incoming;
}
if(outgoing == null) {
throw new Error("outgoing action was null for " + NAME + " filter.");
} else {
this.outgoing = (FilterSupport)outgoing;
}
}
public void init(Workflow next) {
if (next != null) {
this.nextFilter = next;
this.initialized = true;
} else {
log.error("Null filter paramater. " + NAME +
" filter failed to init.");
}
}
/**
* This method will execute the incoming action, process the result String,
* forward control on to the next Workflow component in the Sequence (if
* appropriate), process the Result action, execute the outgoing action and
* return control back into its enclosing Workflow object.
*/
public DataSource forward(
HttpServletRequest request,
HttpServletResponse response,
ServletContext ctx) {
/*
* Right now the Filter will only function if all FilterSupport
* implementations return a SUCCESS string. A standard error handler
* servlet which can output error messages is being defined.
*
* There is a fair bit of error generation code in here, and I'm
* considering adding a standard error handler filter to the platform
* which can sit at the top of the sequence which and handle the
* generation of error messages on the way out the door.
*
*/
if(initialized){
// initialize and execute the incoming action.
incoming.setFilterMetadata(metadata, "incoming");
DataSource incomingFilterResult =
incoming.execute(request, response, ctx);
log.info(incomingFilterResult.toString());
String str = (String) incomingFilterResult.getAttribute("result");
log.info(str);
if(str != null && str.equals("SUCCESS")) {
try {
// forward to next filter
Result actionResult =
(Result)nextFilter.forward(request, response, ctx);
// execute the outgoing action.
outgoing.setFilterMetadata(metadata, "outgoing");
outgoing.setResult(actionResult);
outgoing.execute(request, response, ctx);
return actionResult;
} catch (ClassCastException e) {
log.error("ClassCastException: Action didn't return a" +
" valid Result object");
}
} else {
String errorString = NAME +
"Filter reported a FAILURE. Aborting workflow.";
log.warn(errorString);
Result result = new Result("shocks:FiltrationError");
result.setAttribute("ERROR", errorString);
result.setAttribute("ORIGIN", "Application");
return result;
}
}
String errorString = NAME + "Filter was not initialized. " +
"This is a framework and should be reported " +
"as a bug.";
Result result = new Result("shocks:FiltrationError");
result.setAttribute("ERROR", errorString);
result.setAttribute("ORIGIN", "Framework");
return result;
}
/**
* Returns a clone of the object identical in all regards save its location
* in memory.
*/
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
throw new Error("Error trying to clone the Filter");
}
}
}