/*
* Copyright 2001-2007 Geert Bevin <gbevin[remove] at uwyn dot com>
* Distributed under the terms of either:
* - the common development and distribution license (CDDL), v1.0; or
* - the GNU Lesser General Public License, v2.1 or later
* $Id: ElementContext.java 3813 2007-06-25 18:22:03Z gbevin $
*/
package com.uwyn.rife.engine;
import com.uwyn.rife.engine.exceptions.*;
import com.uwyn.rife.template.*;
import com.uwyn.rife.tools.*;
import java.util.*;
import com.uwyn.rife.authentication.credentialsmanagers.RoleUserAttributes;
import com.uwyn.rife.authentication.credentialsmanagers.RoleUserIdentity;
import com.uwyn.rife.authentication.elements.Identified;
import com.uwyn.rife.config.RifeConfig;
import com.uwyn.rife.continuations.CallState;
import com.uwyn.rife.continuations.ContinuationConfigRuntime;
import com.uwyn.rife.continuations.ContinuationContext;
import com.uwyn.rife.continuations.ContinuationManager;
import com.uwyn.rife.continuations.exceptions.AnswerException;
import com.uwyn.rife.continuations.exceptions.CallException;
import com.uwyn.rife.continuations.exceptions.PauseException;
import com.uwyn.rife.continuations.exceptions.StepBackException;
import com.uwyn.rife.engine.CharSequenceDeferred;
import com.uwyn.rife.site.Constrained;
import com.uwyn.rife.site.ConstrainedProperty;
import com.uwyn.rife.site.ConstrainedUtils;
import com.uwyn.rife.site.FormBuilder;
import com.uwyn.rife.template.exceptions.TemplateException;
import com.uwyn.rife.tools.exceptions.BeanUtilsException;
import com.uwyn.rife.tools.exceptions.LightweightError;
import com.uwyn.rife.tools.exceptions.SerializationUtilsErrorException;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.RequestDispatcher;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
public class ElementContext
{
public static final String PREFIX_EXIT_QUERY = "EXIT:QUERY:";
public static final String PREFIX_EXIT_FORM = "EXIT:FORM:";
public static final String PREFIX_EXIT_PARAMS = "EXIT:PARAMS:";
public static final String PREFIX_EXIT_PARAMSJS = "EXIT:PARAMSJS:";
public static final String PREFIX_SUBMISSION_QUERY = "SUBMISSION:QUERY:";
public static final String PREFIX_SUBMISSION_FORM = "SUBMISSION:FORM:";
public static final String PREFIX_SUBMISSION_PARAMS = "SUBMISSION:PARAMS:";
public static final String PREFIX_SUBMISSION_PARAMSJS = "SUBMISSION:PARAMSJS:";
public static final String PREFIX_PARAM = "PARAM:";
public static final String PREFIX_INPUT = "INPUT:";
public static final String PREFIX_OUTPUT = "OUTPUT:";
public static final String PREFIX_INCOOKIE = "INCOOKIE:";
public static final String PREFIX_OUTCOOKIE = "OUTCOOKIE:";
public static final String PREFIX_ELEMENT = "ELEMENT:";
public static final String PREFIX_PROPERTY = "PROPERTY:";
public static final String PREFIX_OGNL_ROLEUSER = "OGNL:ROLEUSER:";
public static final String PREFIX_MVEL_ROLEUSER = "MVEL:ROLEUSER:";
public static final String PREFIX_GROOVY_ROLEUSER = "GROOVY:ROLEUSER:";
public static final String PREFIX_JANINO_ROLEUSER = "JANINO:ROLEUSER:";
public static final String ID_WEBAPP_ROOTURL = "WEBAPP:ROOTURL";
public static final String ID_SERVER_ROOTURL = "SERVER:ROOTURL";
public static final String TAG_PROPERTY = "^"+PREFIX_PROPERTY+"\\s*(.*?)\\s*$";
public static final String TAG_ELEMENT = "^("+PREFIX_ELEMENT+"\\s*([\\-\\+]?)\\s*(.*?)\\s*)(?::([^:]*))?$";
public static final String TAG_OGNL_ROLEUSER = "(?s)^("+PREFIX_OGNL_ROLEUSER+".*):\\s*\\[\\[\\s*+(.*?)\\s*+\\]\\]\\s*$";
public static final String TAG_MVEL_ROLEUSER = "(?s)^("+PREFIX_MVEL_ROLEUSER+".*):\\s*\\[\\[\\s*+(.*?)\\s*+\\]\\]\\s*$";
public static final String TAG_JANINO_ROLEUSER = "(?s)^("+PREFIX_JANINO_ROLEUSER+".*):\\s*\\[\\[\\s*+(.*?)\\s*+\\]\\]\\s*$";
public static final String TAG_GROOVY_ROLEUSER = "(?s)^("+PREFIX_GROOVY_ROLEUSER+".*):\\s*\\[\\[\\s*+(.*?)\\s*+\\]\\]\\s*$";
private static ThreadLocal<ElementSupport> sActiveElementSupport = new ThreadLocal<ElementSupport>();
private ElementSupport mElement = null;
private ElementInfo mElementInfo = null;
private RequestState mRequestState = null;
private ElementExecutionState mElementState = null;
private Response mResponse = null;
private OutputValues mOutputs = null;
private OutcookieValues mOutcookies = null;
private ArrayList<OutputListener> mOutputListeners = null;
private ArrayList<OutcookieListener> mOutcookieListeners = null;
private String mContextId = null;
private String mSubmission = null;
private boolean mSteppedBack = false;
public static ElementSupport getActiveElementSupport()
{
return sActiveElementSupport.get();
}
ElementContext(ElementSupport element, RequestState state, Response response)
throws EngineException
{
assert element != null;
assert state != null;
assert response != null;
mElement = element;
synchronized (mElement)
{
mElement.setElementContext(this);
mElementInfo = mElement.getElementInfo();
mRequestState = state;
mElementState = mRequestState.getElementState();
mResponse = response;
mOutputs = new OutputValues(this);
mOutcookies = new OutcookieValues(this);
// register the EmbeddingListener of the current state so that the
// output values are kept in sync with global vars and the outcookies
// are kept in sync with the global cookies
if (state.isEmbedded())
{
RequestState.EmbeddingListener listener = state.getEmbeddingListener();
addOutputListener(listener);
addOutcookieListener(listener);
}
// register the PrecedenceListener of the current state so that the
// output values are kept in sync with global vars and the outcookies
// are kept in sync with the global cookies
if (state.isPreceeding())
{
RequestState.PrecedenceListener listener = state.getPrecedenceListener();
addOutputListener(listener);
addOutcookieListener(listener);
}
// if the child element has been reached, replace the request parameters with the
// original child request parameters
if (mElementState.isInheritanceTarget() &&
mElementState.hasRequestParameterValue(ReservedParameters.CHILDREQUEST))
{
ChildRequestEncoder.decode(element.getElementInfo(), mRequestState);
}
// automatically set an output value if the input value has been provided
// and it's a global variable
String[] output_values = null;
for (String globalvar_name : mElementInfo.getGlobalVarNames())
{
if (mElementState.hasInputValue(globalvar_name))
{
output_values = mElementState.getInputValues(globalvar_name);
setAutomatedOutputValues(globalvar_name, output_values);
}
}
}
}
private void handleChildTriggerVariablesPre()
throws EngineException
{
// verify if no value are present that will automatically launch a child trigger
if (mElementInfo.getChildTriggerNames().size() > 0)
{
// check each child trigger for a corresponding value
// if it was found, launch the trigger
for (String child_trigger_name : mElementInfo.getChildTriggerNames())
{
// check if a provided input value is acceptable for this
// element as input or global variable
if (mElementState.hasInputValue(child_trigger_name))
{
if (mElementInfo.containsGlobalVar(child_trigger_name) ||
mElementInfo.containsInput(child_trigger_name))
{
triggerChild(child_trigger_name, getInputValues(child_trigger_name));
continue;
}
}
// check if a provided cookie is acceptable for this
// element as incookie
else if (mRequestState.getCookie(child_trigger_name) != null)
{
if (mElementInfo.containsGlobalCookie(child_trigger_name) ||
mElementInfo.containsIncookie(child_trigger_name))
{
triggerChild(child_trigger_name, new String[] {getCookie(child_trigger_name).getValue()});
continue;
}
}
// check if a default input value is present that can trigger the child
else if (mElementInfo.hasInputDefaultValues(child_trigger_name))
{
triggerChild(child_trigger_name, mElementInfo.getInputDefaultValues(child_trigger_name));
continue;
}
// check if a default cookie value is present that can trigger the child
else if (mElementInfo.hasIncookieDefaultValue(child_trigger_name))
{
triggerChild(child_trigger_name, new String[] {mElementInfo.getIncookieDefaultValue(child_trigger_name)});
continue;
}
// check if a global var default is present for the trigger name
else if (mElementInfo.containsGlobalVar(child_trigger_name) &&
mElementInfo.hasGlobalVarDefaultValues(child_trigger_name))
{
triggerChild(child_trigger_name, mElementInfo.getGlobalVarDefaultValues(child_trigger_name));
continue;
}
// check if a global cookie default is present for the trigger name
else if (mElementInfo.containsGlobalCookie(child_trigger_name) &&
mElementInfo.hasGlobalCookieDefaultValue(child_trigger_name))
{
triggerChild(child_trigger_name, new String[] {mElementInfo.getGlobalCookieDefaultValue(child_trigger_name)});
continue;
}
}
}
}
private void handleChildTriggerVariablesPost()
throws EngineException
{
// verify if no value are present that will automatically launch a child trigger
if (mElementInfo.getChildTriggerNames().size() > 0)
{
// check each child trigger for a corresponding value
// if it was found, launch the trigger
for (String child_trigger_name : mElementInfo.getChildTriggerNames())
{
// check if an output default value is present
if (mElementInfo.hasOutputDefaultValues(child_trigger_name))
{
String[] output_defaultvalues = mElementInfo.getOutputDefaultValues(child_trigger_name);
triggerChild(child_trigger_name, output_defaultvalues);
continue;
}
}
}
}
ElementContext processContext()
throws EngineException
{
long start = mElementInfo.startTrace();
boolean clear_request = false;
ElementContext result = null;
try
{
ElementSupport previous_active_element;
synchronized (mElement)
{
// handle the inheritance structure
if (mElementState.inInheritanceStructure())
{
// try to see if the top of the trigger list matches the current element
if (mElementState.isNextTrigger(mElementInfo))
{
// if it does, and it's a child trigger, use the values to launch a child trigger
if (TriggerContext.TRIGGER_CHILD == mElementState.getNextTriggerType() &&
mElementInfo.containsChildTrigger(mElementState.getNextTriggerName()))
{
triggerChild(mElementState.getNextTriggerName(), mElementState.getNextTriggerValues());
}
else if (TriggerContext.TRIGGER_EXIT == mElementState.getNextTriggerType() &&
mElementInfo.containsExit(mElementState.getNextTriggerName()))
{
exit(mElementState.getNextTriggerName());
}
}
handleChildTriggerVariablesPre();
}
// handle precedence
mRequestState.handlePrecedence(mResponse, getElementInfo());
// set the response content type if this has been specified by the element
if (mElementInfo.getContentType() != null &&
mElementInfo.getContentType().length() > 0)
{
mResponse.setContentType(mElementInfo.getContentType());
}
// obtain the continuation context
ContinuationContext continuation_context = mRequestState.getContinuationContext(mElementInfo);
ContinuationContext.setActiveContext(continuation_context);
ContinuationConfigRuntime.setActiveConfigRuntime(EngineContinuationConfigRuntimeSingleton.INSTANCE);
// register the element as the active one in this thread and remember
// which one that was previously active
previous_active_element = sActiveElementSupport.get();
sActiveElementSupport.set(mElement);
}
try
{
final ElementAware element_aware;
Method submission_handler = null;
synchronized (mElement)
{
// get the element aware interface
element_aware = mElement.getElementAware();
// check if there's are submissions
if (mElementState.hasRequestParameterValue(ReservedParameters.SUBMISSION))
{
String[] submission_names = mElementState.getRequestParameterValues(ReservedParameters.SUBMISSION);
String[] submission_contexts = mElementState.getRequestParameterValues(ReservedParameters.SUBMISSIONCONTEXT);
String submission_context = null;
String submission_context_id = null;
String submission_target = null;
HashSet<String> non_requestparameter_inputs = null;
int counter = 0;
for (String submission_name : submission_names)
{
// get the submission context
if (null == submission_contexts ||
counter >= submission_contexts.length)
{
submission_context = getContextId();
}
else
{
try
{
byte[] decoded = Base64.decode(submission_contexts[counter].getBytes("UTF-8"));
if (decoded != null &&
decoded.length > 0)
{
submission_context = new String(decoded);
}
else
{
submission_context = getContextId();
}
}
catch (UnsupportedEncodingException e)
{
// should never happen
}
}
// split up in the submission context id and the submission target
int seperator_index = submission_context.indexOf("^");
if (-1 == seperator_index)
{
submission_context_id = submission_context;
submission_target = submission_context;
}
else
{
submission_context_id = submission_context.substring(0, seperator_index);
submission_target = submission_context.substring(seperator_index+1);
}
// check if the submission target corresponds to the context id
if (null == mSubmission &&
getContextId().equals(submission_context_id) &&
mElementInfo.hasSubmission(submission_name))
{
mSubmission = submission_name;
}
// if it doesn't, use the submission target element id to
// retrieve the submission declaration, and the parameters
// that have to be disabled as inputs for this element
else
{
// get the submission target
if (0 == submission_target.length())
{
submission_target = getElementInfo().getId();
}
// obtain the element info
ElementInfo submission_target_element = mElementInfo.getSite().resolveId(submission_target);
if (submission_target_element != null)
{
// get the submission declaration
Submission submission = submission_target_element.getSubmission(submission_name);
if (submission != null)
{
// get the submission parameter names
Collection<String> names = submission.getParameterNames();
if (names != null &&
names.size() > 0)
{
if (null == non_requestparameter_inputs)
{
non_requestparameter_inputs = new HashSet<String>();
}
// add the submission parameters to the collection
// of inputs that shouldn't retrieve their values
// from the request parameters
non_requestparameter_inputs.addAll(names);
}
}
}
}
counter++;
}
// register the non parameter inputs
mElementState.setNonRequestParameterInputs(non_requestparameter_inputs);
}
// check if there's a submission handler
// check if a submission is present and a corresponding do*() method is
// available and retrieve the method
final String submission_name = getSubmission();
if (submission_name != null)
{
String submission_handler_name = "do"+StringUtils.capitalize(submission_name);
try
{
submission_handler = element_aware.getClass().getMethod(submission_handler_name, (Class[])null);
submission_handler.setAccessible(true);
}
catch (NoSuchMethodException e)
{
submission_handler = null;
}
catch (SecurityException e)
{
throw new EngineException(e);
}
}
// inject the properties request values into the element instance
new ElementInjector(this).performInjection(submission_name);
// update the target element in the response
mResponse.setLastElement(mElement);
// initialize the element in a fully setup context
mElement.initialize();
}
try
{
try
{
synchronized (mElement)
{
// call the processElement() method of the element itself if no handler could be found
if (null == submission_handler)
{
element_aware.processElement();
}
// call the submission handler if it's available
else
{
try
{
submission_handler.invoke(element_aware, (Object[])null);
}
catch (InvocationTargetException e)
{
if (e.getCause() instanceof LightweightError)
{
throw (LightweightError)e.getCause();
}
else if (e.getCause() instanceof EngineException)
{
throw (EngineException)e.getCause();
}
else
{
throw new EngineException(e.getCause());
}
}
catch (IllegalArgumentException e)
{
throw new EngineException(e);
}
catch (IllegalAccessException e)
{
throw new EngineException(e);
}
}
}
}
catch (CallException e)
{
ContinuationContext context = e.getContext();
// register context
ContinuationManager manager = mElementInfo.getSite().getContinuationManager();
manager.addContext(context);
synchronized (mElement)
{
String exit = (String)e.getTarget();
mElementInfo.validateExitName(exit);
if (null == mElementInfo.getFlowLink(exit))
{
throw new ExitNotAttachedException(mElementInfo.getDeclarationName(), exit);
}
// create a new call state
CallState call_state = new CallState(context.getId(), mElementState.clone());
context.setCreatedCallState(call_state);
// setup the exit
result = setupExitContext(exit);
}
}
}
finally
{
synchronized (mElement)
{
String context_id = getContextId();
ElementResultState result_state = null;
// extract the preserved inputs of this element
Set<Map.Entry<String, String[]>> output_value_entries = mOutputs.aggregateValues().entrySet();
Map<String, String[]> preserved_inputs = collectPreservedInputs(output_value_entries);
// if a call continuation is active, also preserve the previous preserved inputs without overriding the new ones
ContinuationContext active_context = ContinuationContext.getActiveContext();
if (active_context != null &&
active_context.getActiveCallState() != null)
{
ElementResultState previous_result_state = mRequestState.getElementResultStatesRestored().get(context_id);
if (previous_result_state != null)
{
Map<String, String[]> previous_preserved_inputs = previous_result_state.getPreservedInputs();
if (previous_preserved_inputs != null)
{
if (null == preserved_inputs)
{
preserved_inputs = previous_preserved_inputs;
}
else
{
for (Map.Entry<String, String[]> entry : previous_preserved_inputs.entrySet())
{
if (!preserved_inputs.containsKey(entry.getKey()))
{
preserved_inputs.put(entry.getKey(), entry.getValue());
}
}
}
}
}
// preserve the continuation ID of this element
if (null == result_state)
{
result_state = mElementInfo.getStateStore().createNewResultState(context_id);
}
result_state.setContinuationId(active_context.getActiveCallState().getContinuationId());
}
// add the preserved inputs to the result state
if (preserved_inputs != null &&
preserved_inputs.size() > 0)
{
if (null == result_state)
{
result_state = mElementInfo.getStateStore().createNewResultState(context_id);
}
result_state.setPreservedInputs(preserved_inputs);
}
// state the resulting element state
if (result_state != null)
{
mRequestState.getElementResultStatesObtained().put(result_state);
}
// handle the setting of the getter outcookies
mOutcookies.processGetters();
// handle the firing of listener methods for getters outjection
mOutputs.processGetters();
}
// handle the outcookie and output childtriggers from the getters outjection
mOutcookies.processGetterChildTriggers();
mOutputs.processGetterChildTriggers();
}
}
catch (AnswerException e)
{
synchronized (mElement)
{
// only answer a call if a call state is available
// otherwise the answer will function as a regular return
if (e.getContext().getActiveCallState() != null)
{
throw e;
}
}
}
finally
{
synchronized (mElement)
{
// restore the previously active element
sActiveElementSupport.set(previous_active_element);
}
}
synchronized (mElement)
{
// handle the child trigger values that could have an effect after
// the actual element logic
handleChildTriggerVariablesPost();
// handle the default outcookies
if (mElementInfo.hasOutcookieDefaults())
{
Cookie default_cookie = null;
for (Map.Entry<String, String> default_outcookie_entry : mElementInfo.getDefaultOutcookies().entrySet())
{
if (!mOutcookies.contains(default_outcookie_entry.getKey()))
{
default_cookie = new Cookie(default_outcookie_entry.getKey(), default_outcookie_entry.getValue());
default_cookie.setPath("");
setCookie(default_cookie);
}
}
}
// handle the default global cookies
if (mElementInfo.hasGlobalCookieDefaults())
{
Cookie default_cookie = null;
for (Map.Entry<String, String> default_globalcookie_entry : mElementInfo.getDefaultGlobalCookies().entrySet())
{
if (!mOutcookies.contains(default_globalcookie_entry.getKey()))
{
default_cookie = new Cookie(default_globalcookie_entry.getKey(), default_globalcookie_entry.getValue());
default_cookie.setPath("");
setCookie(default_cookie);
}
}
}
}
}
catch (PauseException e)
{
ContinuationContext context = e.getContext();
// register context
ContinuationManager manager = mElementInfo.getSite().getContinuationManager();
manager.addContext(context);
synchronized (mElement)
{
// preserve the continuation ID of this element
String context_id = getContextId();
ElementResultState result_state = mRequestState.getElementResultStatesObtained().get(context_id);
if (null == result_state)
{
result_state = mElementInfo.getStateStore().createNewResultState(context_id);
mRequestState.getElementResultStatesObtained().put(result_state);
}
result_state.setContinuationId(context.getId());
clear_request = true;
try
{
mResponse.flush();
}
catch (EngineException e2)
{
// if errors occurred during flushing it means that the client has
// disconnected, disregard them
}
mResponse = null;
}
}
catch (ChildTriggeredException e)
{
synchronized (mElement)
{
result = setupChildtriggerContext(e.getChildTriggerName(), e.getChildTriggerValues());
}
}
catch (ExitTriggeredException e)
{
synchronized (mElement)
{
result = handleExitTrigger(e.getExitName());
}
}
catch (StepBackException e)
{
ContinuationContext context = e.getContext();
// register context
ContinuationManager manager = mElementInfo.getSite().getContinuationManager();
manager.addContext(context);
synchronized (mElement)
{
// preserve the continuation ID of this element
String context_id = getContextId();
ElementResultState result_state = mRequestState.getElementResultStatesObtained().get(context_id);
if (null == result_state)
{
result_state = mElementInfo.getStateStore().createNewResultState(context_id);
mRequestState.getElementResultStatesObtained().put(result_state);
}
result_state.setContinuationId(context.getId());
// try to obtain the id of the previous continuation
String stepbackid = e.lookupStepBackId();
// there is no previous continuation, so start from the beginning again
if (null == stepbackid)
{
ContinuationContext.clearActiveContext();
mRequestState.setContinuationId(null);
}
else
{
mRequestState.setContinuationId(stepbackid);
}
result = new ElementContext(mElement, mRequestState, mResponse);
result.mSteppedBack = true;
}
}
catch (ForwardException e)
{
synchronized (mElement)
{
handleForward(e.getUrl());
}
}
catch (RedirectException e)
{
synchronized (mElement)
{
getResponse().sendRedirect(e.getUrl());
}
}
finally
{
synchronized (mElement)
{
try
{
// flush the output buffer
if (mResponse != null)
{
mResponse.flush();
}
// trace element activity
mElementInfo.outputTrace(start, mRequestState);
}
catch (EngineException e)
{
// if errors occurred during flushing it means that the client has
// disconnected, disregard them
}
finally
{
// clear the request if this is needed, this typically happens
// for continuations, to prevent the request to be cloned when
// element instances are cloned
if (clear_request)
{
mRequestState.clearRequest();
}
}
}
}
return result;
}
private ElementContext setupChildtriggerContext(String childtrigger, String[] values)
throws EngineException
{
ElementContext element_context = null;
Map<String, String[]> child_inputs = null;
if (mElementState.inInheritanceStructure())
{
// construct the child element
ElementInfo child_element_info = mElementState.getInheritanceStack().pop();
// verify if the trigger wasn't raised automatically, if this is the
// case, the first trigger context has to be removed from the trigger
// list since it has been used by this element
if (mElementState.isNextChildTrigger(mElementInfo, childtrigger))
{
// obtain the stored exit inputs
child_inputs = mElementState.nextTrigger().getParameters();
}
// since the current element deferred the logical flow to its child,
// record the child trigger that caused this
else
{
child_inputs = getChildInputValues(child_element_info);
// don't store an child trigger which isn't dependent on watched values in the
// trigger list, the whole element will be executed each time for those triggers
if (childtrigger != null)
{
mElementState.addTrigger(TriggerContext.generateChildTrigger(mElementInfo, childtrigger, values, child_inputs));
}
}
// construct the child element's context
mElementState.setTriggerInputs(child_inputs);
element_context = mRequestState.getElementContext(child_element_info, mResponse);
}
return element_context;
}
private ElementContext handleExitTrigger(String exit)
throws EngineException
{
// get the the flowlink to check first if it's a redirection
FlowLink flowlink = mElementInfo.getFlowLink(exit);
if (null == flowlink)
{
throw new ExitNotAttachedException(mElementInfo.getDeclarationName(), exit);
}
if (flowlink.isRedirect())
{
getResponse().sendRedirect(_getExitQueryUrl(flowlink, null, mOutputs.aggregateValues(), null).toString());
return null;
}
else
{
return setupExitContext(exit);
}
}
private ElementContext setupExitContext(String exit)
throws EngineException
{
// get the element info of the exit target
FlowLink flowlink = mElementInfo.getFlowLink(exit);
if (null == flowlink)
{
throw new ExitNotAttachedException(mElementInfo.getDeclarationName(), exit);
}
ElementInfo target = flowlink.getExitTarget(mRequestState);
// handle embedding cancellation
if (mRequestState.isEmbedded() &&
flowlink.cancelEmbedding())
{
// this flag is set in the embedding context to indicate that the
// embedding needs to be cancelled, it will be checked by the
// processEmbeddedElement method of the embedding element
mRequestState.getEmbeddingContext().setCancelEmbedding(true);
// clear all current output buffers
RequestState request_state = mRequestState;
while (request_state.isEmbedded())
{
request_state.getEmbeddingContext().getElementContext().getResponse().clearBuffer();
request_state = request_state.getEmbeddingContext().getElementContext().getRequestState();
}
}
Map<String, String[]> exit_request_params = null;
Map<String, String[]> exit_inputs = null;
Stack<ElementInfo> inheritance_stack = null;
Set<Map.Entry<String, String[]>> output_entries = mOutputs.aggregateValues().entrySet();
if (mElementState.inInheritanceStructure() &&
!flowlink.cancelInheritance())
{
// verify if the trigger wasn't raised automatically, if this is the
// case, the first trigger context has to be removed from the trigger
// list since it has been used by this element
if (mElementState.isNextExitTrigger(mElementInfo, exit))
{
exit_request_params = mElementState.getRequestParameters();
// obtain the stored exit inputs
exit_inputs = mElementState.nextTrigger().getParameters();
}
// since the current element deferred the logical flow to an exit,
// record this action in the trigger list
else
{
exit_request_params = new HashMap<String, String[]>();
exit_request_params.put(ReservedParameters.CHILDREQUEST, new String[] {getEncodedChildRequest()});
exit_request_params.put(ReservedParameters.TRIGGERLIST, mElementState.getRequestParameterValues(ReservedParameters.TRIGGERLIST));
exit_inputs = getExitInputValues(flowlink, output_entries, target, flowlink.isSnapback());
mElementState.addTrigger(TriggerContext.generateExitTrigger(mElementInfo, exit, exit_inputs));
}
inheritance_stack = mElementState.getInheritanceStack();
// check for successive inheritance stacks
Stack<ElementInfo> dest_inheritance_stack = target.getInheritanceStack();
if (dest_inheritance_stack != null)
{
inheritance_stack.addAll(dest_inheritance_stack);
target = inheritance_stack.pop();
}
}
else
{
exit_request_params = new HashMap<String, String[]>();
exit_inputs = getExitInputValues(flowlink, output_entries, target, flowlink.isSnapback());
mRequestState.setTarget(target);
// obtain the inheritance stack and if it exists the top parent
// this isn't done if an inheritance structure is already present
Stack<ElementInfo> dest_inheritance_stack = target.getInheritanceStack();
if (dest_inheritance_stack != null)
{
inheritance_stack = new Stack<ElementInfo>();
inheritance_stack.addAll(dest_inheritance_stack);
target = inheritance_stack.pop();
}
}
// the request method isn't get or post anymore since all parameters have
// been removed
mElementState.setMethod(RequestMethod.EXIT);
// construct the target element's context
mElementState.setRequestParameters(exit_request_params);
mElementState.setInheritanceStack(inheritance_stack);
mElementState.setTriggerInputs(exit_inputs);
// return the new element context
return mRequestState.getElementContext(target, mResponse);
}
private void handleForward(String url)
{
boolean is_absolute_url = true;
if (-1 == url.indexOf(":/"))
{
is_absolute_url = false;
StringBuilder absolute_url = new StringBuilder();
absolute_url.append(mRequestState.getWebappRootUrl(RifeConfig.Engine.getLocalForwardPort()));
if (url.startsWith("/"))
{
absolute_url.append(url.substring(1));
}
else
{
absolute_url.append(url);
}
url = absolute_url.toString();
}
try
{
Map<String, String> request_header_map = new HashMap<String, String>();
Request request = mRequestState.getRequest();
Enumeration<String> request_header_names = request.getHeaderNames();
// convert the headers to a map
if (request_header_names.hasMoreElements())
{
String header_name = null;
String header_name_lowercase = null;
String header_value = null;
do
{
header_name = request_header_names.nextElement();
if (null != header_name)
{
header_name_lowercase = header_name.toLowerCase();
header_value = request.getHeader(header_name);
if (is_absolute_url &&
("host".equals(header_name_lowercase) ||
"connection".equals(header_name_lowercase) ||
"keep-alive".equals(header_name_lowercase) ||
"content-type".equals(header_name_lowercase) ||
"content-length".equals(header_name_lowercase)))
{
continue;
}
request_header_map.put(header_name, header_value);
}
}
while (request_header_names.hasMoreElements());
}
// retrieve the page
HttpUtils.Page page = new HttpUtils.Request(url).headers(request_header_map).retrieve();
// incorporate the page data in the current request
if ((page.getResponseCode() / 100) != 2)
{
// report errors
mResponse.sendError(page.getResponseCode(), page.getResponseMessage());
}
else
{
// preserve the status code
mResponse.setStatus(page.getResponseCode());
}
if (page.getContent() != null)
{
mResponse.print(page.getContent());
}
for (Map.Entry<String, List<String>> header : page.getHeaders().entrySet())
{
if (header.getKey() != null)
{
String key = header.getKey().toLowerCase();
// strip out several duplicate headers
if (key.equals("accept-encoding") ||
key.equals("content-encoding") ||
key.equals("content-length") ||
key.equals("date") ||
key.equals("host") ||
key.equals("server") ||
key.equals("transfer-encoding"))
{
continue;
}
// handle the content type differently
if (key.equals("content-type"))
{
mResponse.setContentType(HttpUtils.extractMimeTypeFromContentType(page.getContentType()));
continue;
}
for (String header_value : header.getValue())
{
mResponse.addHeader(header.getKey(), header_value);
}
}
}
}
catch (IOException e)
{
mResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
}
RequestDispatcher dispatcher = mRequestState.getRequest().getRequestDispatcher(url);
if (null == dispatcher)
{
mResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
}
}
RequestState getRequestState()
{
return mRequestState;
}
ElementInfo getElementInfo()
{
return mElementInfo;
}
ElementSupport getElementSupport()
{
return mElement;
}
ElementExecutionState getElementState()
{
return mElementState;
}
Response getResponse()
{
return mResponse;
}
void setResponse(Response response)
{
mResponse = response;
}
Template getHtmlTemplate(String name, String encoding, TemplateTransformer transformer)
throws TemplateException
{
if (null == name) throw new IllegalArgumentException("name can't be null.");
if (0 == name.length()) throw new IllegalArgumentException("name can't be empty.");
return TemplateFactory.ENGINEHTML.get(name, encoding, transformer);
}
Template getXhtmlTemplate(String name, String encoding, TemplateTransformer transformer)
throws TemplateException
{
if (null == name) throw new IllegalArgumentException("name can't be null.");
if (0 == name.length()) throw new IllegalArgumentException("name can't be empty.");
return TemplateFactory.ENGINEXHTML.get(name, encoding, transformer);
}
Template getXmlTemplate(String name, String encoding, TemplateTransformer transformer)
throws TemplateException
{
if (null == name) throw new IllegalArgumentException("name can't be null.");
if (0 == name.length()) throw new IllegalArgumentException("name can't be empty.");
return TemplateFactory.ENGINEXML.get(name, encoding, transformer);
}
Template getTxtTemplate(String name, String encoding, TemplateTransformer transformer)
throws TemplateException
{
if (null == name) throw new IllegalArgumentException("name can't be null.");
if (0 == name.length()) throw new IllegalArgumentException("name can't be empty.");
return TemplateFactory.ENGINETXT.get(name, encoding, transformer);
}
void processEmbeddedElementsEarly(Template template, ElementSupport embeddingElement)
{
// process the embedded elements
if (template.hasFilteredValues(TAG_ELEMENT))
{
List<String[]> element_tags = template.getFilteredValues(TAG_ELEMENT);
for (String[] captured_groups : element_tags)
{
// only embed the element if the value hasn't been set in the
// template yet and is declared as 'early'
if (!template.isValueSet(captured_groups[0]) &&
captured_groups[2].equals("-"))
{
processEmbeddedElement(captured_groups[0], template, embeddingElement, captured_groups[3], captured_groups[4], null);
}
}
for (String[] captured_groups : element_tags)
{
// only embed the element if the value hasn't been set in the
// template yet and has no specific priority
if (!template.isValueSet(captured_groups[0]) &&
0 == captured_groups[2].length())
{
processEmbeddedElement(captured_groups[0], template, embeddingElement, captured_groups[3], captured_groups[4], null);
}
}
}
}
void processEmbeddedElementsLate(Template template, ElementSupport embeddingElement)
{
// process the embedded elements
if (template.hasFilteredValues(TAG_ELEMENT))
{
List<String[]> element_tags = template.getFilteredValues(TAG_ELEMENT);
for (String[] captured_groups : element_tags)
{
// only embed the element if the value hasn't been set in the
// template yet and is declared as late
if (!template.isValueSet(captured_groups[0]) &&
captured_groups[2].equals("+"))
{
processEmbeddedElement(captured_groups[0], template, embeddingElement, captured_groups[3], captured_groups[4], null);
}
}
}
}
void print(Template template)
throws TemplateException, EngineException
{
List<String> set_values = processTemplate(template);
// set the content type
if (!mResponse.isContentTypeSet())
{
String content_type = template.getDefaultContentType();
if (null == content_type)
{
content_type = RifeConfig.Engine.getDefaultContentType();
}
mResponse.setContentType(content_type);
}
// print the element contents with the auto-generated values
mResponse.print(template);
// clean up the values that were set
template.removeValues(set_values);
}
List<String> processTemplate(Template template)
throws TemplateException, EngineException
{
List<String> set_values = new ArrayList<String>();
// pre-obtain the output entries, since they process the outjection logic
Map<String, String[]> output_value_map = mOutputs.aggregateValues();
Set<Map.Entry<String, String[]>> output_value_entries = output_value_map.entrySet();
// retrieve the template encoder
TemplateEncoder encoder = template.getEncoder();
// process the filtered roleuser tags
evaluateExpressionRoleUserTags(set_values, template, null);
// create values for the exit urls
Set<Map.Entry<String, FlowLink>> exit_entries = mElementInfo.getExitEntries();
if (exit_entries.size() > 0)
{
String exit_name = null;
FlowLink exit_flowlink = null;
String exit_query_value_id = null;
String exit_form_value_id = null;
String exit_params_value_id = null;
String exit_paramsjs_value_id = null;
for (Map.Entry<String, FlowLink> exit_entry : exit_entries)
{
if (exit_entry.getValue() != null)
{
exit_name = exit_entry.getKey();
exit_flowlink = exit_entry.getValue();
exit_query_value_id = PREFIX_EXIT_QUERY+exit_name;
exit_form_value_id = PREFIX_EXIT_FORM+exit_name;
exit_params_value_id = PREFIX_EXIT_PARAMS+exit_name;
exit_paramsjs_value_id = PREFIX_EXIT_PARAMS+exit_name;
if (template.hasValueId(exit_query_value_id) &&
!template.isValueSet(exit_query_value_id))
{
template.setValue(exit_query_value_id, _getExitQueryUrl(exit_flowlink, null, output_value_map, null).encoder(encoder));
set_values.add(exit_query_value_id);
}
if (template.hasValueId(exit_form_value_id))
{
// only substitute the template value if it hasn't been specified yet
// this allows for user overriding
if (!template.isValueSet(exit_form_value_id))
{
template.setValue(exit_form_value_id, _getExitFormUrl(exit_flowlink, null, output_value_map).encoder(encoder));
set_values.add(exit_form_value_id);
}
// only substitute the form parameters template value if the url is present
if (template.hasValueId(exit_params_value_id))
{
// only substitute the template value if it hasn't been specified yet
// this allows for user overriding
if (!template.isValueSet(exit_params_value_id))
{
template.setValue(exit_params_value_id, _getExitFormParameters(exit_flowlink, output_value_map, null));
set_values.add(exit_params_value_id);
}
}
else if (template.hasValueId(exit_paramsjs_value_id))
{
// only substitute the template value if it hasn't been specified yet
// this allows for user overriding
if (!template.isValueSet(exit_paramsjs_value_id))
{
template.setValue(exit_paramsjs_value_id, _getExitFormParametersJavascript(exit_flowlink, output_value_map, null));
set_values.add(exit_paramsjs_value_id);
}
}
else
{
throw new EngineException("The required template value '"+exit_params_value_id+"' is not present. Replacement of the template value '"+exit_form_value_id+"' alone is not sufficient.");
}
}
else
{
if (template.hasValueId(exit_params_value_id))
{
throw new EngineException("The template value '"+exit_params_value_id+"' was specified, while the template value '"+exit_form_value_id+"' could not be found. This is not sufficient, both are needed.");
}
else if (template.hasValueId(exit_paramsjs_value_id))
{
throw new EngineException("The template value '"+exit_paramsjs_value_id+"' was specified, while the template value '"+exit_form_value_id+"' could not be found. This is not sufficient, both are needed.");
}
}
}
}
}
// create values for submission urls
String submission_query_value_id = null;
String submission_form_value_id = null;
String submission_params_value_id = null;
String submission_paramsjs_value_id = null;
for (String submission_name : mElementInfo.getSubmissionNames())
{
submission_query_value_id = PREFIX_SUBMISSION_QUERY+submission_name;
submission_form_value_id = PREFIX_SUBMISSION_FORM+submission_name;
submission_params_value_id = PREFIX_SUBMISSION_PARAMS+submission_name;
submission_paramsjs_value_id = PREFIX_SUBMISSION_PARAMSJS+submission_name;
if (template.hasValueId(submission_query_value_id) &&
!template.isValueSet(submission_query_value_id))
{
template.setValue(submission_query_value_id, _getSubmissionQueryUrl(submission_name, null, null, output_value_entries).encoder(encoder));
set_values.add(submission_query_value_id);
}
if (template.hasValueId(submission_form_value_id))
{
// only substitute the template value if it hasn't been specified yet
// this allows for user overriding
if (!template.isValueSet(submission_form_value_id))
{
template.setValue(submission_form_value_id, getSubmissionFormUrl(null).encoder(encoder));
set_values.add(submission_form_value_id);
}
// only substitute the form parameters template value if the url is present
if (template.hasValueId(submission_params_value_id))
{
// only substitute the template value if it hasn't been specified yet
// this allows for user overriding
if (!template.isValueSet(submission_params_value_id))
{
template.setValue(submission_params_value_id, _getSubmissionFormParameters(submission_name, null, output_value_entries));
set_values.add(submission_params_value_id);
}
}
else if (template.hasValueId(submission_paramsjs_value_id))
{
// only substitute the template value if it hasn't been specified yet
// this allows for user overriding
if (!template.isValueSet(submission_paramsjs_value_id))
{
template.setValue(submission_paramsjs_value_id, _getSubmissionFormParametersJavascript(submission_name, null, output_value_entries));
set_values.add(submission_paramsjs_value_id);
}
}
else
{
throw new EngineException("The template value '"+submission_params_value_id+"' nor '"+submission_paramsjs_value_id+"'are not present. Replacement of the template value '"+submission_form_value_id+"' alone is not sufficient.");
}
}
else
{
if (template.hasValueId(submission_params_value_id))
{
throw new EngineException("The template value '"+submission_params_value_id+"' was specified, while the template value '"+submission_form_value_id+"' could not be found. This is not sufficient, both are needed.");
}
else if (template.hasValueId(submission_paramsjs_value_id))
{
throw new EngineException("The template value '"+submission_paramsjs_value_id+"' was specified, while the template value '"+submission_form_value_id+"' could not be found. This is not sufficient, both are needed.");
}
}
}
// create values for properties
if (template.hasFilteredValues(TAG_PROPERTY))
{
String property_value_id = null;
String property_value = null;
for (String[] property_tag : template.getFilteredValues(TAG_PROPERTY))
{
property_value_id = PREFIX_PROPERTY+property_tag[1];
if (template.hasValueId(property_value_id) &&
!template.isValueSet(property_value_id))
{
property_value = mElementInfo.getPropertyString(property_tag[1]);
if (property_value != null)
{
template.setValue(property_value_id, encoder.encode(property_value));
set_values.add(property_value_id);
}
}
}
}
// create values for inputs
String input_value_id = null;
String[] input_values = null;
for (Map.Entry<String, String[]> input_entry : mElementState.getInputEntries())
{
if (mElementInfo.containsInput(input_entry.getKey()) &&
mElementState.hasInputValue(input_entry.getKey()))
{
input_value_id = PREFIX_INPUT+input_entry.getKey();
input_values = input_entry.getValue();
if (template.hasValueId(input_value_id) &&
!template.isValueSet(input_value_id))
{
template.setValue(input_value_id, encoder.encode(input_values[0]));
set_values.add(input_value_id);
}
set_values.addAll(selectInputParameter(template, input_entry.getKey(), input_values));
}
}
// create values for outputs
String output_value_id = null;
for (Map.Entry<String, String[]> output_entry : output_value_entries)
{
output_value_id = PREFIX_OUTPUT+output_entry.getKey();
if (template.hasValueId(output_value_id) &&
!template.isValueSet(output_value_id) &&
output_entry.getValue() != null)
{
template.setValue(output_value_id, encoder.encode(output_entry.getValue()[0]));
set_values.add(output_value_id);
}
}
// create values for global variables
for (String globalvar_name : mElementInfo.getGlobalVarNames())
{
if(mElementState.hasInputValue(globalvar_name))
{
input_value_id = PREFIX_INPUT+globalvar_name;
if (template.hasValueId(input_value_id) &&
!template.isValueSet(input_value_id))
{
template.setValue(input_value_id, encoder.encode(mElementState.getInput(globalvar_name)));
set_values.add(input_value_id);
}
set_values.addAll(selectInputParameter(template, globalvar_name, mElementState.getInputValues(globalvar_name)));
}
String[] global_output_value = output_value_map.get(globalvar_name);
if (global_output_value != null)
{
output_value_id = PREFIX_OUTPUT+globalvar_name;
if (template.hasValueId(output_value_id) &&
!template.isValueSet(output_value_id))
{
template.setValue(output_value_id, encoder.encode(global_output_value[0]));
set_values.add(output_value_id);
}
}
}
// create values for in cookies
String incookie_value_id = null;
for (Map.Entry<String, String> incookie_entry : getIncookieEntries())
{
if (mElementInfo.containsIncookie(incookie_entry.getKey()) ||
mElementInfo.containsGlobalCookie(incookie_entry.getKey()))
{
incookie_value_id = PREFIX_INCOOKIE+incookie_entry.getKey();
if (template.hasValueId(incookie_value_id) &&
!template.isValueSet(incookie_value_id))
{
template.setValue(incookie_value_id, encoder.encode(incookie_entry.getValue()));
set_values.add(incookie_value_id);
}
}
}
// create values for out cookies
String outcookie_value_id = null;
for (Map.Entry<String, String> outcookie_entry : mOutcookies.aggregateValues().entrySet())
{
if (mElementInfo.containsOutcookiePossibility(outcookie_entry.getKey()))
{
outcookie_value_id = PREFIX_OUTCOOKIE+outcookie_entry.getKey();
if (template.hasValueId(outcookie_value_id) &&
!template.isValueSet(outcookie_value_id))
{
template.setValue(outcookie_value_id, encoder.encode(outcookie_entry.getValue()));
set_values.add(outcookie_value_id);
}
}
}
// set the webapp root
if (template.hasValueId(ID_WEBAPP_ROOTURL) &&
!template.isValueSet(ID_WEBAPP_ROOTURL))
{
template.setValue(ID_WEBAPP_ROOTURL, mRequestState.getWebappRootUrl(-1));
set_values.add(ID_WEBAPP_ROOTURL);
}
// set the server root
if (template.hasValueId(ID_SERVER_ROOTURL) &&
!template.isValueSet(ID_SERVER_ROOTURL))
{
template.setValue(ID_SERVER_ROOTURL, mRequestState.getServerRootUrl(-1));
set_values.add(ID_SERVER_ROOTURL);
}
// create values for submission parameters and beans
String[] submission_param_values = null;
String submission_param_value_id = null;
for (Submission submission : mElementInfo.getSubmissions())
{
// create the parameters
for (String submission_param_name : submission.getParameterNames())
{
if (mElementState.hasRequestParameterValue(submission_param_name))
{
submission_param_values = mElementState.getRequestParameterValues(submission_param_name);
submission_param_value_id = PREFIX_PARAM+submission_param_name;
if (template.hasValueId(submission_param_value_id) &&
!template.isValueSet(submission_param_value_id))
{
template.setValue(submission_param_value_id, encoder.encode(submission_param_values[0]));
set_values.add(submission_param_value_id);
}
set_values.addAll(selectSubmissionParameter(template, submission_param_name, submission_param_values));
}
}
// create the bean forms
BeanHandler bean_handler = template.getBeanHandler();
if (bean_handler != null)
{
FormBuilder form_builder = bean_handler.getFormBuilder();
if (form_builder != null)
{
for (BeanDeclaration bean : submission.getBeans())
{
try
{
Map<String, String[]> parameters = null;
if (hasSubmission() &&
submission.getName().equals(getSubmission()))
{
parameters = mElementState.getRequestParameters();
}
form_builder.generateForm(template, bean.getBeanClass(), parameters, bean.getPrefix());
}
catch (Throwable e)
{
throw new SubmissionBeanFormGenerationErrorException(mElementInfo.getDeclarationName(), submission.getName(), bean.getClassname(), e);
}
}
}
}
}
// process the late embedded elements
processEmbeddedElementsLate(template, mElement);
return set_values;
}
void triggerChild(String childTriggerName, String[] childTriggerValues)
throws EngineException
{
mElement.enableRequestAccess(false);
try
{
if (mElement.childTriggered(childTriggerName, childTriggerValues))
{
throw new ChildTriggeredException(childTriggerName, childTriggerValues);
}
}
finally
{
mElement.enableRequestAccess(true);
}
}
boolean hasSubmission()
{
return null != getSubmission();
}
boolean hasSubmission(String name)
{
String submission = getSubmission();
return submission != null &&
submission.equals(name);
}
String getSubmission()
{
if (null == mSubmission)
{
return null;
}
return mSubmission;
}
private void validateParameter(String parameterName)
throws EngineException
{
assert parameterName != null;
assert parameterName.length() > 0;
boolean found = false;
for (Submission submission : mElementInfo.getSubmissions())
{
if (submission.containsParameter(parameterName))
{
found = true;
break;
}
}
if (!found)
{
throw new ParameterUnknownException(mElementInfo.getDeclarationName(), parameterName);
}
}
private void validateFile(String fileName)
throws EngineException
{
assert fileName != null;
assert fileName.length() > 0;
boolean found = false;
for (Submission submission : mElementInfo.getSubmissions())
{
if (submission.containsFile(fileName))
{
found = true;
break;
}
}
if (!found)
{
throw new FileUnknownException(mElementInfo.getDeclarationName(), fileName);
}
}
boolean isInputEmpty(String name)
throws EngineException
{
String input = getInput(name);
return null == input ||
input.trim().equals("");
}
String getInput(String name)
throws EngineException
{
assert name != null;
assert name.length() > 0;
mElementInfo.validateInputName(name);
String input = mElementState.getInput(name);
if (null == input &&
mElementInfo.hasInputDefaults())
{
String[] default_values = mElementInfo.getInputDefaultValues(name);
if (default_values != null)
{
input = default_values[0];
}
}
if (null == input &&
mElementInfo.hasGlobalVarDefaults())
{
String[] default_values = mElementInfo.getGlobalVarDefaultValues(name);
if (default_values != null)
{
input = default_values[0];
}
}
return input;
}
String[] getInputValues(String name)
throws EngineException
{
assert name != null;
assert name.length() > 0;
mElementInfo.validateInputName(name);
String[] input_values = mElementState.getInputValues(name);
if (null == input_values &&
mElementInfo.hasInputDefaults())
{
input_values = mElementInfo.getInputDefaultValues(name);
}
if (null == input_values &&
mElementInfo.hasGlobalVarDefaults())
{
input_values = mElementInfo.getGlobalVarDefaultValues(name);
}
return input_values;
}
boolean hasInputValue(String name)
throws EngineException
{
assert name != null;
assert name.length() > 0;
mElementInfo.validateInputName(name);
return mElementState.hasInputValue(name) || mElementInfo.hasInputDefaultValues(name) || mElementInfo.hasGlobalVarDefaultValues(name);
}
Collection<String> selectInputParameter(Template template, String name, String[] values)
{
return selectParameter(template, PREFIX_INPUT+name, values);
}
OutputValues getOutputs()
{
return mOutputs;
}
void setOutput(String name, String value)
throws EngineException
{
assert name != null;
assert name.length() > 0;
assert value != null;
mElementInfo.validateOutputName(name);
// create a string array
String[] value_array = new String[]{value};
// store the value
setOutputValues(name, value_array);
if (mElementState.inInheritanceStructure() &&
mElementInfo.containsChildTrigger(name))
{
triggerChild(name, value_array);
}
}
void setOutput(String name, String[] values)
throws EngineException
{
assert name != null;
assert name.length() > 0;
assert values != null;
assert values.length > 0;
mElementInfo.validateOutputName(name);
setOutputValues(name, values);
if (mElementState.inInheritanceStructure() &&
mElementInfo.containsChildTrigger(name))
{
triggerChild(name, values);
}
}
void setOutput(String name, Object value, ConstrainedProperty constrainedProperty)
throws EngineException
{
assert name != null;
assert name.length() > 0;
assert value != null;
String[] value_array = getOutputObjectValues(name, value, constrainedProperty);
// store the value
setOutputValues(name, value_array);
if (mElementState.inInheritanceStructure() &&
mElementInfo.containsChildTrigger(name))
{
triggerChild(name, value_array);
}
}
private String[] getOutputObjectValues(String name, Object value, ConstrainedProperty constrainedProperty)
throws EngineException
{
mElementInfo.validateOutputName(name);
// create a string array
String[] value_array = null;
// convert the value to a string representation
Class value_type = value.getClass();
if (value_type.isArray() ||
!(value instanceof Serializable) ||
ClassUtils.isBasic(value_type))
{
value_array = ArrayUtils.createStringArray(value, constrainedProperty);
}
else
{
try
{
value_array = new String[]{SerializationUtils.serializeToString((Serializable)value)};
}
catch (SerializationUtilsErrorException e)
{
throw new UnserializableOutputValueException(mElementInfo.getDeclarationName(), name, value, e);
}
}
return value_array;
}
void addOutputValue(String name, String value)
throws EngineException
{
assert name != null;
assert name.length() > 0;
assert value != null;
mElementInfo.validateOutputName(name);
String[] value_array = null;
String[] existing_values = mOutputs.get(name);
if (existing_values != null)
{
value_array = ArrayUtils.join(existing_values, value);
}
else
{
value_array = new String[]{value};
}
setOutputValues(name, value_array);
if (mElementState.inInheritanceStructure() &&
mElementInfo.containsChildTrigger(name))
{
triggerChild(name, value_array);
}
}
void addOutputValues(String name, String[] values)
throws EngineException
{
assert name != null;
assert name.length() > 0;
assert values != null;
assert values.length > 0;
mElementInfo.validateOutputName(name);
String[] value_array = null;
String[] existing_values = mOutputs.get(name);
if (existing_values != null)
{
value_array = ArrayUtils.join(existing_values, values);
}
else
{
value_array = values;
}
setOutputValues(name, value_array);
if (mElementState.inInheritanceStructure() &&
mElementInfo.containsChildTrigger(name))
{
triggerChild(name, value_array);
}
}
void addOutputValue(String name, Object value)
throws EngineException
{
assert name != null;
assert name.length() > 0;
assert value != null;
mElementInfo.validateOutputName(name);
// convert the value to a string representation
String value_text = null;
Class value_type = value.getClass();
if (!(value instanceof Serializable) ||
ClassUtils.isBasic(value_type))
{
value_text = String.valueOf(value);
}
else if (value instanceof Serializable)
{
try
{
value_text = SerializationUtils.serializeToString((Serializable)value);
}
catch (SerializationUtilsErrorException e)
{
throw new UnserializableOutputValueException(mElementInfo.getDeclarationName(), name, value, e);
}
}
else
{
value_text = String.valueOf(value);
}
addOutputValue(name, value_text);
}
void clearOutput(String name)
throws EngineException
{
assert name != null;
assert name.length() > 0;
mElementInfo.validateOutputName(name);
clearOutputValue(name);
}
void clearNamedOutputBean(String name)
throws EngineException
{
assert name != null;
mElementInfo.validateOutbeanName(name);
BeanDeclaration output_bean = mElementInfo.getNamedOutbeanInfo(name);
if (null == output_bean)
{
output_bean = mElementInfo.getNamedGlobalBeanInfo(name);
}
Class output_bean_class = null;
try
{
output_bean_class = Class.forName(output_bean.getClassname());
}
catch (ClassNotFoundException e)
{
throw new NamedOutbeanClassnameErrorException(mElementInfo.getDeclarationName(),name, output_bean.getClassname());
}
clearOutputBean(output_bean_class, output_bean.getPrefix());
}
void clearOutputBean(Class beanClass, String prefix)
throws EngineException
{
if (null == beanClass) throw new IllegalArgumentException("beanClass can't be null.");
try
{
// handle outputs
Collection<String> output_names = mElementInfo.getOutputNames();
String[] output_names_array = new String[output_names.size()];
output_names.toArray(output_names_array);
// handle globals
Collection<String> globalvar_names = mElementInfo.getGlobalVarNames();
String[] globalvar_names_array = new String[globalvar_names.size()];
globalvar_names.toArray(globalvar_names_array);
// merge the both arrays
String[] merged_names_array = ArrayUtils.join(output_names_array, globalvar_names_array);
// process all the possible output names
Set<String> property_names = BeanUtils.getPropertyNames(beanClass, merged_names_array, null, prefix);
for (String property_name : property_names)
{
clearOutput(property_name);
}
}
catch (BeanUtilsException e)
{
throw new BeanClassNamesErrorException(beanClass, e);
}
}
String[] getOutput(String name)
throws EngineException
{
mElementInfo.validateOutputName(name);
return mOutputs.aggregateValues().get(name);
}
private Set<Map.Entry<String, String>> getIncookieEntries()
{
return getCookieValues().entrySet();
}
boolean hasCookie(String name)
throws EngineException
{
assert name != null;
assert name.length() > 0;
mElementInfo.validateIncookieName(name);
return mRequestState.hasCookie(name) || mElementInfo.hasIncookieDefaultValue(name) || mElementInfo.hasGlobalCookieDefaultValue(name);
}
Cookie getCookie(String name)
throws EngineException
{
assert name != null;
assert name.length() > 0;
mElementInfo.validateIncookieName(name);
Cookie cookie = mRequestState.getCookie(name);
if (null == cookie )
{
if (mElementInfo.hasIncookieDefaultValue(name))
{
cookie = new Cookie(name, mElementInfo.getIncookieDefaultValue(name));
}
if (mElementInfo.hasGlobalCookieDefaultValue(name))
{
cookie = new Cookie(name, mElementInfo.getGlobalCookieDefaultValue(name));
}
}
return cookie;
}
String getCookieValue(String name)
throws EngineException
{
Cookie cookie = getCookie(name);
String value = null;
if (cookie != null)
{
value = cookie.getValue();
}
return value;
}
void setCookie(Cookie cookie)
throws EngineException
{
assert cookie != null;
assert cookie.getName() != null;
mElementInfo.validateOutcookieName(cookie.getName());
mOutcookies.put(cookie.getName(), cookie.getValue());
setCookieRaw(cookie);
if (mElementState.inInheritanceStructure() &&
mElementInfo.containsChildTrigger(cookie.getName()))
{
triggerChild(cookie.getName(), new String[] {cookie.getValue()});
}
}
void setCookieRaw(Cookie cookie)
{
mResponse.addCookie(cookie);
mRequestState.setStateCookie(cookie);
fireOutcookieSet(cookie);
}
HashMap<String, String> getCookieValues()
throws EngineException
{
HashMap<String, String> result = new HashMap<String, String>();
for (Map.Entry<String, String> entry : mElementInfo.getDefaultIncookies().entrySet())
{
result.put(entry.getKey(), entry.getValue());
}
for (Map.Entry<String, String> entry : mElementInfo.getDefaultGlobalCookies().entrySet())
{
result.put(entry.getKey(), entry.getValue());
}
for (Map.Entry<String, Cookie> entry : mRequestState.getCookies().entrySet())
{
result.put(entry.getKey(), entry.getValue().getValue());
}
return result;
}
boolean hasParameterValue(String name)
throws EngineException
{
assert name != null;
assert name.length() > 0;
validateParameter(name);
String submission = getSubmission();
if (null == submission)
{
return false;
}
return mElementState.hasRequestParameterValue(name) || mElementInfo.hasParameterDefaultValues(submission, name);
}
boolean isParameterEmpty(String name)
throws EngineException
{
assert name != null;
assert name.length() > 0;
String parameter = getParameter(name);
if (null == parameter ||
parameter.trim().equals(""))
{
return true;
}
return false;
}
String getParameter(String name)
throws EngineException
{
assert name != null;
assert name.length() > 0;
validateParameter(name);
String submission = getSubmission();
if (null == submission)
{
return null;
}
String parameter = mElementState.getRequestParameter(name);
if (null == parameter &&
mElementInfo.hasParameterDefaults(submission))
{
String[] default_values = mElementInfo.getParameterDefaultValues(submission, name);
if (default_values != null)
{
return default_values[0];
}
}
return parameter;
}
ArrayList<String> getParameterNames(String regexp)
throws EngineException
{
Pattern pattern = null;
if (regexp != null)
{
pattern = Pattern.compile("^"+regexp+"$");
}
ArrayList<String> result = new ArrayList<String>();
String submission_name = getSubmission();
if (null == submission_name)
{
return result;
}
Submission submission = mElementInfo.getSubmission(submission_name);
if (null == submission)
{
return result;
}
Collection<String> parameter_names = null;
// add all default parameters that match
parameter_names = submission.getParameterDefaultNames();
for (String parameter_name : parameter_names)
{
if (null == pattern ||
pattern.matcher(parameter_name).matches())
{
result.add(parameter_name);
}
}
// go over the possible parameters and check if they have values in the request
parameter_names = submission.getParameterNames();
for (String parameter_name : parameter_names)
{
if (mElementState.hasRequestParameterValue(parameter_name) &&
!result.contains(parameter_name) &&
(null == pattern || pattern.matcher(parameter_name).matches()))
{
result.add(parameter_name);
}
}
// go over all the parameter regexps and find those that match with the parameters in the request
Matcher matcher = null;
for (Pattern parameter_regexp : submission.getParameterRegexps())
{
for (String parameter_name : mElementState.getRequestParameterNames())
{
matcher = parameter_regexp.matcher(parameter_name);
if (matcher.matches())
{
if (mElementState.hasRequestParameterValue(parameter_name) &&
!result.contains(parameter_name) &&
(null == pattern || pattern.matcher(parameter_name).matches()))
{
result.add(parameter_name);
}
}
}
}
return result;
}
String[] getParameterValues(String name)
throws EngineException
{
assert name != null;
assert name.length() > 0;
validateParameter(name);
String submission = getSubmission();
if (null == submission)
{
return null;
}
String[] parameter_values = mElementState.getRequestParameterValues(name);
if (null == parameter_values &&
mElementInfo.hasParameterDefaults(submission))
{
return mElementInfo.getParameterDefaultValues(submission, name);
}
return parameter_values;
}
ArrayList<String> getUploadedFileNames(String regexp)
throws EngineException
{
Pattern pattern = null;
if (regexp != null)
{
pattern = Pattern.compile("^"+regexp+"$");
}
ArrayList<String> result = new ArrayList<String>();
String submission_name = getSubmission();
if (null == submission_name)
{
return result;
}
Submission submission = mElementInfo.getSubmission(submission_name);
if (null == submission)
{
return result;
}
Collection<String> file_names = null;
// go over the possible files and check if they have values in the request
file_names = submission.getFileNames();
for (String file_name : file_names)
{
if (mRequestState.hasUploadedFile(file_name) &&
!result.contains(file_name) &&
(null == pattern || pattern.matcher(file_name).matches()))
{
result.add(file_name);
}
}
// go over all the file regexps and find those that match with the files in the request
Matcher matcher = null;
for (Pattern file_regexp : submission.getFileRegexps())
{
for (String file_name : mRequestState.getUploadedFileNames())
{
matcher = file_regexp.matcher(file_name);
if (matcher.matches())
{
if (mRequestState.hasUploadedFile(file_name) &&
!result.contains(file_name) &&
(null == pattern || pattern.matcher(file_name).matches()))
{
result.add(file_name);
}
}
}
}
return result;
}
ArrayList<String> getUploadedFileNames()
throws EngineException
{
ArrayList<String> result = new ArrayList<String>();
String submission_name = getSubmission();
if (null == submission_name)
{
return result;
}
Submission submission = mElementInfo.getSubmission(submission_name);
if (null == submission)
{
return result;
}
Collection<String> file_names = submission.getFileNames();
for (String file_name : file_names)
{
if (mRequestState.hasUploadedFile(file_name))
{
result.add(file_name);
}
}
return result;
}
boolean hasUploadedFile(String name)
throws EngineException
{
assert name != null;
assert name.length() > 0;
validateFile(name);
String submission = getSubmission();
if (null == submission)
{
return false;
}
return mRequestState.hasUploadedFile(name);
}
boolean isFileEmpty(String name)
throws EngineException
{
assert name != null;
assert name.length() > 0;
UploadedFile file = getUploadedFile(name);
return null == file ||
null == file.getFile() ||
0 == file.getFile().length();
}
UploadedFile getUploadedFile(String name)
throws EngineException
{
assert name != null;
assert name.length() > 0;
validateFile(name);
String submission = getSubmission();
if (null == submission)
{
return null;
}
return mRequestState.getUploadedFile(name);
}
UploadedFile[] getUploadedFiles(String name)
throws EngineException
{
assert name != null;
assert name.length() > 0;
validateFile(name);
String submission = getSubmission();
if (null == submission)
{
return null;
}
return mRequestState.getUploadedFiles(name);
}
void setOutputValues(String name, String[] values)
{
assert name != null;
assert name.length() > 0;
assert values != null;
mOutputs.put(name, values);
fireOutputValueSet(name, values);
}
void setAutomatedOutputValues(String name, String[] values)
{
mOutputs.putFallback(name, values);
fireAutomatedOutputValueSet(name, values);
}
void clearOutputValue(String name)
{
assert name != null;
assert name.length() > 0;
// clearing the output value instead of removing it, this prevents
// later automated processing to fill it in again
mOutputs.put(name, null);
fireOutputValueCleared(name);
}
void clearAutomatedOutputValue(String name)
{
// clearing the output value instead of removing it, this prevents
// later automated processing to fill it in again
mOutputs.putFallback(name, null);
fireAutomatedOutputValueCleared(name);
}
void addOutputListener(OutputListener listener)
{
if (null == mOutputListeners)
{
mOutputListeners = new ArrayList<OutputListener>();
}
mOutputListeners.add(listener);
}
void removeOutputListener(OutputListener listener)
{
mOutputListeners.remove(listener);
}
void fireOutputValueSet(String name, String[] values)
{
if (null == mOutputListeners)
{
return;
}
for (OutputListener listener : mOutputListeners)
{
listener.outputValueSet(name, values);
}
}
void fireOutputValueCleared(String name)
{
if (null == mOutputListeners)
{
return;
}
for (OutputListener listener : mOutputListeners)
{
listener.outputValueCleared(name);
}
}
void fireAutomatedOutputValueSet(String name, String[] values)
{
if (null == mOutputListeners)
{
return;
}
for (OutputListener listener : mOutputListeners)
{
listener.automatedOutputValueSet(name, values);
}
}
void fireAutomatedOutputValueCleared(String name)
{
if (null == mOutputListeners)
{
return;
}
for (OutputListener listener : mOutputListeners)
{
listener.automatedOutputValueCleared(name);
}
}
void addOutcookieListener(OutcookieListener listener)
{
if (null == mOutcookieListeners)
{
mOutcookieListeners = new ArrayList<OutcookieListener>();
}
mOutcookieListeners.add(listener);
}
void removeOutcookieListener(OutcookieListener listener)
{
mOutcookieListeners.remove(listener);
}
void fireOutcookieSet(Cookie cookie)
{
if (null == mOutcookieListeners)
{
return;
}
for (OutcookieListener listener : mOutcookieListeners)
{
listener.outcookieSet(cookie);
}
}
void child()
throws EngineException
{
throw new ChildTriggeredException(null, null);
}
void defer()
throws EngineException
{
throw new DeferException();
}
void forward(String url)
throws EngineException
{
throw new ForwardException(url);
}
void redirect(String url)
{
throw new RedirectException(url);
}
boolean duringStepBack()
{
return mSteppedBack;
}
void exit(String name)
throws EngineException
{
assert name != null;
assert name.length() > 0;
mElementInfo.validateExitName(name);
throw new ExitTriggeredException(name);
}
/**
* Retrieves the inputs values that a child receives when the parent
* delegates the control flow to it. This is based on the current output
* values of the parent element, combined with the global variables
*/
private Map<String, String[]> getChildInputValues(ElementInfo targetElement)
{
Map<String, String[]> inputs = null;
inputs = mElementState.getTriggerInputs();
if (null == inputs)
{
inputs = mElementState.getRequestParameters();
}
if (mElementInfo.hasGlobalVars() &&
targetElement.hasGlobalVars())
{
String[] input_values_array = null;
for (Map.Entry<String, String[]> output_entry : mOutputs.aggregateValues().entrySet())
{
// create automatic data link for global variables
if (mElementInfo.containsGlobalVar(output_entry.getKey()) &&
targetElement.containsGlobalVar(output_entry.getKey()))
{
input_values_array = output_entry.getValue();
inputs.put(output_entry.getKey(), input_values_array);
}
}
}
return inputs;
}
/**
* Retrieves the inputs values that an exit receives when it is
* followed. This is based on the current output values of the
* active element.
*/
private HashMap<String, String[]> getExitInputValues(FlowLink flowLink, Set<Map.Entry<String, String[]>> outputEntries, ElementInfo target, boolean snapback)
throws EngineException
{
HashMap<String, String[]> inputs = new HashMap<String, String[]>();
// preserve the embedding element's inputs and global vars
if (target.getId().equals(mElementInfo.getId()))
{
ElementContext context = this;
while (context != null &&
context.mRequestState.isEmbedded())
{
context = context.mRequestState.getEmbeddingContext().getElementContext();
for (String input_name : context.mElementInfo.getInputNames())
{
if (context.mElementState.hasInputValue(input_name))
{
inputs.put(input_name, context.mElementState.getInputValues(input_name));
}
}
for (String globalvar_name : context.mElementInfo.getGlobalVarNames())
{
if (context.mElementState.hasInputValue(globalvar_name))
{
inputs.put(globalvar_name, context.mElementState.getInputValues(globalvar_name));
}
}
}
}
if (mElementInfo.hasSnapbackDataLinks() ||
mElementInfo.hasDataLink(target) ||
(mElementInfo.hasGlobalVars() &&
target.hasGlobalVars()))
{
HashMap<String, String[]> dest_input_candidates = new HashMap<String, String[]>();
// if the exit is reflective, preserve the input values that have
// identically named output values
if (target == mElementInfo)
{
Collection<String> input_names = mElementInfo.getInputNames();
Collection<String> output_names = mElementInfo.getOutputNames();
Iterator<String> input_names_it = input_names.iterator();
String input_name = null;
String[] input_values = null;
while (input_names_it.hasNext())
{
input_name = input_names_it.next();
if (output_names.contains(input_name))
{
input_values = getInputValues(input_name);
if (input_values != null)
{
dest_input_candidates.put(input_name, input_values);
}
}
}
}
// add the global default values
GlobalVar globalvar_data = null;
for (Map.Entry<String, GlobalVar> globalvar_entry : mElementInfo.getGlobalVarEntries())
{
globalvar_data = globalvar_entry.getValue();
if (globalvar_data != null &&
globalvar_data.getDefaultValues() != null)
{
dest_input_candidates.put(globalvar_entry.getKey(), globalvar_data.getDefaultValues());
}
}
// add the output values
String[] output_values_array = null;
for (Map.Entry<String, String[]> output_entry : outputEntries)
{
output_values_array = output_entry.getValue();
dest_input_candidates.put(output_entry.getKey(), output_values_array);
}
// process the exit input value candidates
Collection<String> dest_input_names = null;
GlobalVar globalvar_source = null;
GlobalVar globalvar_target = null;
for (String candidate : dest_input_candidates.keySet())
{
if (!mElementInfo.containsDepartureVar(candidate))
{
// create automatic data link for global variables
if (mElementInfo.containsGlobalVar(candidate) &&
target.containsGlobalVar(candidate))
{
globalvar_source = mElementInfo.getGlobalVarInfo(candidate);
globalvar_target = target.getGlobalVarInfo(candidate);
// only create the link if the global vars are in the
// same group scope
if (globalvar_source.getGroupId() == globalvar_target.getGroupId())
{
inputs.put(candidate, dest_input_candidates.get(candidate));
}
}
// translate outputs to inputs through a possible data link
dest_input_names = mElementInfo.getDataLinkInputs(candidate, target, snapback, flowLink);
if (dest_input_names != null)
{
for (String dest_input_name : dest_input_names)
{
inputs.put(dest_input_name, dest_input_candidates.get(candidate));
}
}
}
}
}
return inputs;
}
private void appendTargetAndPathinfo(StringBuilder url, String targetUrl, String pathinfo)
{
url.append(targetUrl);
// append the optional pathinfo
if (pathinfo != null &&
pathinfo.length() > 0)
{
// ensure that the pathinfo is prefixed with a /
if (url.charAt(url.length()-1) != '/')
{
url.append("/");
}
url.append(StringUtils.stripFromFront(pathinfo, "/"));
}
}
private String getExitUrl(FlowLink flowlink, String pathInfo)
throws EngineException
{
assert flowlink != null;
String url = null;
String pathinfo = null;
// obtain the declared flowlink target element and determine what the
// actual target element is according to the inheritance status
ElementInfo flowlink_target = flowlink.getExitTarget(mRequestState);
ElementInfo context_target = null;
if (mElementState.inInheritanceStructure() &&
!flowlink.cancelInheritance())
{
context_target = mRequestState.getTarget();
}
else
{
context_target = flowlink_target;
}
url = context_target.getUrl();
// if the element defined no url and the flowlink target points to the element
// itself when it's embedded, go up the hierarchy of embedded elements
// to grab the first defined element url
if (null == url)
{
if (!mRequestState.isEmbedded() &&
!flowlink_target.getId().equals(mElementInfo.getId()))
{
throw new ExitTargetUrlMissingException(mElementInfo.getDeclarationName(), flowlink.getExitName(), context_target.getDeclarationName());
}
ElementContext context = this;
while (null == url &&
context != null &&
context.mRequestState.isEmbedded())
{
context = context.mRequestState.getEmbeddingContext().getElementContext();
if (context.getElementInfo().isPathInfoUsed())
{
pathinfo = context.mRequestState.getElementState().getPathInfo();
}
else
{
pathinfo = null;
}
if (context.mElementState.inInheritanceStructure())
{
url = context.mRequestState.getTarget().getUrl();
}
else
{
url = context.mElementInfo.getUrl();
}
}
}
// apply a forced pathinfo
if (pathInfo != null &&
pathInfo.length() > 0)
{
pathinfo = pathInfo;
}
// construct the correct servlet path and url that points to the
// target child element, or the current element if there are no children
StringBuilder url_buffer = new StringBuilder(mRequestState.getGateUrl());
appendTargetAndPathinfo(url_buffer, url, pathinfo);
return url_buffer.toString();
}
private Map<String, String[]> overrideOutputValues(Map<String, String[]> outputValueMap, String[] outputValues)
throws EngineException
{
if (null == outputValues ||
0 == outputValues.length)
{
return outputValueMap;
}
Map<String, String[]> outputs = new HashMap<String, String[]>(outputValueMap);
// store the output overrides
for (int i = 0; i < outputValues.length; i += 2)
{
outputs.put(outputValues[i], new String[]{outputValues[i+1]});
}
return outputs;
}
private Map<String, String[]> getExitInputValues(FlowLink flowLink, ElementInfo target, boolean snapback, Map<String, String[]> outputValueMap, String[] outputValues)
throws EngineException
{
// override current output values
Map<String, String[]> overridden_outputs = overrideOutputValues(outputValueMap, outputValues);
// construct the exit input parameters
return getExitInputValues(flowLink, overridden_outputs.entrySet(), target, snapback);
}
private FlowState _getExitParameters(FlowLink flowlink, ElementInfo contextTarget, Map<String, String[]> outputValueMap, String[] outputValues)
{
FlowState state = new FlowState();
// construct the exit input parameters
Map<String, String[]> inputs = getExitInputValues(flowlink, flowlink.getTarget(), flowlink.isSnapback(), outputValueMap, outputValues);
// Create or preserve the request parameters that were initially send to the child element
// this permits completely seperate processing of any other parameters.
// Maintain a stack of successful parent elements.
if (mElementState.inInheritanceStructure() &&
!flowlink.cancelInheritance())
{
state.putParameter(ReservedParameters.CHILDREQUEST, getEncodedChildRequest());
// preserve the trigger list
List<TriggerContext> new_trigger_context = mElementState.cloneTriggerList();
new_trigger_context.add(TriggerContext.generateExitTrigger(mElementInfo, flowlink.getExitName(), inputs));
state.putParameter(ReservedParameters.TRIGGERLIST, TriggerListEncoder.encode(new_trigger_context));
}
else
{
// construct the exit input parameters
state.setParameters(inputs);
}
if (!flowlink.cancelContinuations())
{
// Preserve the continuation id if a continuation context is active
// and the exit goes back to the same element
if (mElementInfo == flowlink.getTarget())
{
String continuation_id = ContinuationContext.getActiveContextId();
if (continuation_id != null)
{
state.putParameter(ReservedParameters.CONTID, continuation_id);
}
}
}
return state;
}
CharSequenceDeferred getExitFormUrl(String name, String pathinfo)
throws EngineException
{
assert name != null;
assert name.length() > 0;
mElementInfo.validateExitName(name);
FlowLink flowlink = null;
flowlink = mElementInfo.getFlowLink(name);
if (null == flowlink)
{
throw new ExitNotAttachedException(mElement.getElementInfo().getDeclarationName(), name);
}
return _getExitFormUrl(flowlink, pathinfo, mOutputs.aggregateValues());
}
private CharSequenceDeferred _getExitFormUrl(FlowLink flowlink, String pathinfo, Map<String, String[]> outputValueMap)
throws EngineException
{
assert flowlink != null;
ElementInfo flowlink_target = flowlink.getExitTarget(mRequestState);
StateStore state_store = flowlink_target.getStateStore();
// process the pathinfo mappings
if (null == pathinfo &&
flowlink_target.isPathInfoUsed())
{
FlowState state = _getExitParameters(flowlink, flowlink_target, outputValueMap, null);
pathinfo = handlePathInfoMapping(flowlink_target, state, pathinfo);
}
return new CharSequenceFormUrl(state_store, getExitUrl(flowlink, pathinfo));
}
CharSequenceDeferred getExitFormParameters(String name, String[] outputValues)
throws EngineException
{
assert name != null;
assert name.length() > 0;
assert outputValues == null || outputValues.length % 2 == 0;
mElementInfo.validateExitName(name);
FlowLink flowlink = null;
flowlink = mElementInfo.getFlowLink(name);
if (null == flowlink)
{
throw new ExitNotAttachedException(mElement.getElementInfo().getDeclarationName(), name);
}
return _getExitFormParameters(flowlink, mOutputs.aggregateValues(), outputValues);
}
CharSequenceDeferred getExitFormParametersJavascript(String name, String[] outputValues)
throws EngineException
{
assert name != null;
assert name.length() > 0;
assert outputValues == null || outputValues.length % 2 == 0;
mElementInfo.validateExitName(name);
FlowLink flowlink = null;
flowlink = mElementInfo.getFlowLink(name);
if (null == flowlink)
{
throw new ExitNotAttachedException(mElement.getElementInfo().getDeclarationName(), name);
}
return _getExitFormParametersJavascript(flowlink, mOutputs.aggregateValues(), outputValues);
}
private CharSequenceDeferred _getExitFormParameters(FlowLink flowlink, Map<String, String[]> outputValueMap, String[] outputValues)
throws EngineException
{
assert flowlink != null;
ElementInfo flowlink_target = flowlink.getExitTarget(mRequestState);
FlowState state = _getExitParameters(flowlink, flowlink_target, outputValueMap, outputValues);
return new CharSequenceFormState(flowlink_target.getStateStore(), state, FormStateType.PARAMS);
}
private CharSequenceDeferred _getExitFormParametersJavascript(FlowLink flowlink, Map<String, String[]> outputValueMap, String[] outputValues)
throws EngineException
{
assert flowlink != null;
ElementInfo flowlink_target = flowlink.getExitTarget(mRequestState);
FlowState state = _getExitParameters(flowlink, flowlink_target, outputValueMap, outputValues);
return new CharSequenceFormState(flowlink_target.getStateStore(), state, FormStateType.JAVASCRIPT);
}
CharSequenceDeferred getExitQueryUrl(String name, String pathinfo, String[] outputValues)
throws EngineException
{
assert name != null;
assert name.length() > 0;
assert outputValues == null || outputValues.length % 2 == 0;
mElementInfo.validateExitName(name);
FlowLink flowlink = null;
flowlink = mElementInfo.getFlowLink(name);
if (null == flowlink)
{
throw new ExitNotAttachedException(mElement.getElementInfo().getDeclarationName(), name);
}
return _getExitQueryUrl(flowlink, pathinfo, mOutputs.aggregateValues(), outputValues);
}
private CharSequenceDeferred _getExitQueryUrl(FlowLink flowlink, String pathinfo, Map<String, String[]> outputValueMap, String[] outputValues)
throws EngineException
{
assert flowlink != null;
ElementInfo flowlink_target = flowlink.getExitTarget(mRequestState);
// process the exit url query parameters
StateStore state_store = flowlink_target.getStateStore();
FlowState state = _getExitParameters(flowlink, flowlink_target, outputValueMap, outputValues);
// process the pathinfo mappings
if (null == pathinfo &&
flowlink_target.isPathInfoUsed())
{
pathinfo = handlePathInfoMapping(flowlink_target, state, pathinfo);
}
return new CharSequenceQueryUrl(state_store, getExitUrl(flowlink, pathinfo), state, mElementInfo, "exit", flowlink.getExitName());
}
private String handlePathInfoMapping(ElementInfo flowlinkTarget, FlowState state, String pathinfo)
{
Map<String, String[]> parameters = state.getParameters();
mapping:
for (PathInfoMapping mapping : flowlinkTarget.getPathInfoMappings())
{
if (parameters.keySet().containsAll(mapping.getInputs()))
{
Iterator<String> inputs_it = mapping.getInputs().iterator();
StringBuilder builder = new StringBuilder();
String input_name;
String[] input_value;
for (PathInfoMappingSegment segment : mapping.getSegments())
{
if (segment.isRegexp())
{
if (!inputs_it.hasNext())
{
continue mapping;
}
input_name = inputs_it.next();
// ensure that the input has only got one value
input_value = parameters.get(input_name);
if (null == input_value ||
input_value.length != 1)
{
continue mapping;
}
// ensure that the input value corresponds to the
// regexp pattern for it
Matcher matcher = segment.getPattern().matcher(input_value[0]);
if (!matcher.matches())
{
continue mapping;
}
// add the url-encoded input value to the pathinfo
builder.append(StringUtils.encodeUrl(input_value[0]));
}
else
{
builder.append(segment.getValue());
}
}
// remove the input parameters that are handled by the pathinfo
for (String input : mapping.getInputs())
{
parameters.remove(input);
}
// build the new pathinfo
return builder.toString();
}
}
return null;
}
void setExitQuery(Template template, String name, String pathinfo, String[] outputValues)
throws TemplateException, EngineException
{
template.setValue(PREFIX_EXIT_QUERY+name, getExitQueryUrl(name, pathinfo, outputValues).encoder(EncoderHtml.getInstance()));
}
void setExitForm(Template template, String name, String pathinfo, String[] outputValues)
throws TemplateException, EngineException
{
template.setValue(PREFIX_EXIT_FORM+name, getExitFormUrl(name, pathinfo).encoder(EncoderHtml.getInstance()));
String exit_javascript = PREFIX_EXIT_PARAMSJS+name;
if (template.hasValueId(exit_javascript))
{
template.setValue(exit_javascript, getExitFormParameters(name, outputValues));
}
else
{
template.setValue(PREFIX_EXIT_PARAMS+name, getExitFormParameters(name, outputValues));
}
}
Collection<String> selectParameter(Template template, String name, String[] values)
{
assert name != null;
assert name.length() > 0;
BeanHandler bean_handler = template.getBeanHandler();
if (null == bean_handler)
{
return Collections.EMPTY_LIST;
}
FormBuilder form_builder = bean_handler.getFormBuilder();
if (null == form_builder)
{
return Collections.EMPTY_LIST;
}
return form_builder.selectParameter(template, name, values);
}
void generateForm(Template template, Object beanInstance, String prefix)
throws EngineException
{
BeanHandler bean_handler = template.getBeanHandler();
if (null == bean_handler)
{
return;
}
FormBuilder form_builder = bean_handler.getFormBuilder();
if (null == form_builder)
{
return;
}
try
{
form_builder.removeForm(template, beanInstance.getClass(), prefix);
form_builder.generateForm(template, beanInstance, null, prefix);
}
catch (BeanUtilsException e)
{
throw new EngineException(e);
}
}
void generateEmptyForm(Template template, Class beanClass, String prefix)
throws EngineException
{
BeanHandler bean_handler = template.getBeanHandler();
if (null == bean_handler)
{
return;
}
FormBuilder form_builder = bean_handler.getFormBuilder();
if (null == form_builder)
{
return;
}
try
{
form_builder.removeForm(template, beanClass, prefix);
form_builder.generateForm(template, beanClass, null, prefix);
}
catch (BeanUtilsException e)
{
throw new EngineException(e);
}
}
void removeForm(Template template, Class beanClass, String prefix)
throws EngineException
{
BeanHandler bean_handler = template.getBeanHandler();
if (null == bean_handler)
{
return;
}
FormBuilder form_builder = bean_handler.getFormBuilder();
if (null == form_builder)
{
return;
}
try
{
form_builder.removeForm(template, beanClass, prefix);
}
catch (BeanUtilsException e)
{
throw new EngineException(e);
}
}
private String getContextId()
{
if (mContextId != null)
{
return mContextId;
}
synchronized (mElement)
{
mContextId = mRequestState.buildContextId();
}
return mContextId;
}
private FlowState getSubmissionParameters(String name, String[] parameterValues, Set<Map.Entry<String, String[]>> outputEntries)
{
FlowState state = new FlowState();
state.putParameter(ReservedParameters.SUBMISSION, name);
// add the submission parameters
if (parameterValues != null)
{
String parameter_name = null;
String parameter_value = null;
for (int i = 0; i < parameterValues.length; i += 2)
{
parameter_name = parameterValues[i];
parameter_value = parameterValues[i+1];
state.putParameter(parameter_name, parameter_value);
}
validateParameter(parameter_name);
}
// Create the submission context parameter
Submission submission = mElementInfo.getSubmission(name);
if (null == submission ||
Scope.LOCAL == submission.getScope())
{
String submission_context = getContextId();
String target = getElementInfo().getId();
if (!submission_context.equals(target))
{
StringBuilder submission_context_buffer = new StringBuilder(submission_context);
submission_context_buffer.append("^");
submission_context_buffer.append(target);
submission_context = submission_context_buffer.toString();
}
try
{
state.putParameter(ReservedParameters.SUBMISSIONCONTEXT, Base64.encodeToString(submission_context.getBytes("UTF-8"), false));
}
catch (UnsupportedEncodingException e)
{
// should never happen
}
}
// Preserve the continuation ID if a continuation context is active
if (null == submission ||
!submission.getCancelContinuations())
{
String continuation_id = ContinuationContext.getActiveContextId();
if (continuation_id != null)
{
state.putParameter(ReservedParameters.CONTID, continuation_id);
}
}
// create or preserve the request parameters that were initially send to the child element
// this permits completely seperate processing of any other parameters
if (mElementState.inInheritanceStructure())
{
// preserve the original child request
state.putParameter(ReservedParameters.CHILDREQUEST, getEncodedChildRequest());
// preserve the trigger list
state.putParameter(ReservedParameters.TRIGGERLIST, mElementState.encodeTriggerList());
}
// preserve the embedding element's inputs and global vars
ElementContext context = this;
while (context != null &&
context.mRequestState.isEmbedded())
{
context = context.mRequestState.getEmbeddingContext().getElementContext();
for (String input_name : context.mElementInfo.getInputNames())
{
if (context.mElementState.hasInputValue(input_name))
{
state.putSubmissionGlobalInput(input_name, context.mElementState.getInputValues(input_name, false));
}
}
for (String globalvar_name : context.mElementInfo.getGlobalVarNames())
{
if (context.mElementState.hasInputValue(globalvar_name))
{
state.putSubmissionGlobalInput(globalvar_name, context.mElementState.getInputValues(globalvar_name, false));
}
}
}
// preserve the global variables
for (String globalvar_name : mElementInfo.getGlobalVarNames())
{
if (mElementState.hasInputValue(globalvar_name))
{
state.putSubmissionGlobalInput(globalvar_name, mElementState.getInputValues(globalvar_name, false));
}
}
// activate reflective datalinks for global vars
if (outputEntries != null)
{
for (Map.Entry<String, String[]> output : outputEntries)
{
// global vars
if (mElementInfo.containsGlobalVar(output.getKey()))
{
state.putSubmissionGlobalInput(output.getKey(), output.getValue());
}
}
}
// add this element's inputs
Map<String, String[]> element_inputs = null;
// preserve the input values
for (String input_name : mElementInfo.getInputNames())
{
if (mElementState.hasInputValue(input_name))
{
if (null == element_inputs)
{
element_inputs = new LinkedHashMap<String, String[]>();
}
element_inputs.put(input_name, mElementState.getInputValues(input_name));
}
}
// merge this element's inputs with its preserved inputs
Map<String, String[]> preserved_inputs = collectPreservedInputs(outputEntries);
String context_id = getContextId();
if (preserved_inputs != null &&
preserved_inputs.size() > 0)
{
if (null == element_inputs)
{
element_inputs = new LinkedHashMap<String, String[]>();
}
element_inputs.putAll(preserved_inputs);
}
state.setSubmissionElementInputs(element_inputs);
// remember this element's context identifier for when the context inputs are extracted
state.setSubmissionContextId(context_id);
return state;
}
private Map<String, String[]> collectPreservedInputs(Set<Map.Entry<String, String[]>> outputEntries)
{
Map<String, String[]> element_inputs = null;
// activate reflective datalinks for which outputs point to the inputs
if (outputEntries != null)
{
for (Map.Entry<String, String[]> output : outputEntries)
{
// reflective datalinks
Collection<String> datalink_inputs = mElementInfo.getDataLinkInputs(output.getKey(), mElementInfo, false, null);
if (datalink_inputs != null)
{
for (String input_name : datalink_inputs)
{
if (null == element_inputs)
{
element_inputs = new LinkedHashMap<String, String[]>();
}
element_inputs.put(input_name, output.getValue());
}
}
}
}
return element_inputs;
}
private String getSubmissionUrl(String pathInfo)
{
String url = null;
String pathinfo = null;
if (mElementInfo.isPathInfoUsed())
{
pathinfo = mRequestState.getElementState().getPathInfo();
}
if (mElementState.inInheritanceStructure())
{
url = mRequestState.getTarget().getUrl();
}
else
{
url = mElementInfo.getUrl();
}
// if the element defined no url, go up the hierarchy of embedded elements
// to grab the first defined element url
if (null == url)
{
if (!mRequestState.isEmbedded())
{
if (mElementState.inInheritanceStructure())
{
throw new SubmissionInheritanceUrlMissingException(mRequestState.getTarget().getDeclarationName(), mElementInfo.getDeclarationName());
}
else
{
throw new SubmissionUrlMissingException(mElementInfo.getDeclarationName());
}
}
ElementContext context = this;
while (null == url &&
context != null &&
context.mRequestState.isEmbedded())
{
context = context.mRequestState.getEmbeddingContext().getElementContext();
if (context.getElementInfo().isPathInfoUsed())
{
pathinfo = context.mRequestState.getElementState().getPathInfo();
}
else
{
pathinfo = null;
}
if (context.mElementState.inInheritanceStructure())
{
url = context.mRequestState.getTarget().getUrl();
}
else
{
url = context.mElementInfo.getUrl();
}
}
}
// apply a forced pathinfo
if (pathInfo != null &&
pathInfo.length() > 0)
{
pathinfo = pathInfo;
}
// construct the correct servlet path and url that points to the
// target child element, or the current element if there are no children
StringBuilder url_buffer = new StringBuilder(mRequestState.getGateUrl());
appendTargetAndPathinfo(url_buffer, url, pathinfo);
return url_buffer.toString();
}
private CharSequenceDeferred _getSubmissionQueryUrl(String name, String pathinfo, String[] parameterValues, Set<Map.Entry<String, String[]>> outputEntries)
throws EngineException
{
StateStore state_store = mElementInfo.getStateStore();
FlowState state = getSubmissionParameters(name, parameterValues, outputEntries);
return new CharSequenceQueryUrl(state_store, getSubmissionUrl(pathinfo), state, mElementInfo, "submission", name);
}
CharSequenceDeferred getSubmissionQueryUrl(String name, String pathinfo, String[] parameterValues)
throws EngineException
{
assert name != null;
assert name.length() > 0;
assert parameterValues == null || parameterValues.length % 2 == 0;
mElementInfo.validateSubmissionName(name);
return _getSubmissionQueryUrl(name, pathinfo, parameterValues, mOutputs.aggregateValues().entrySet());
}
CharSequenceDeferred getSubmissionFormUrl(String pathinfo)
throws EngineException
{
return new CharSequenceFormUrl(mElementInfo.getStateStore(), getSubmissionUrl(pathinfo));
}
CharSequenceDeferred getSubmissionFormParameters(String name, String[] parameterValues)
throws EngineException
{
assert name != null;
assert name.length() > 0;
assert parameterValues == null || parameterValues.length % 2 == 0;
mElementInfo.validateSubmissionName(name);
return _getSubmissionFormParameters(name, parameterValues, mOutputs.aggregateValues().entrySet());
}
CharSequenceDeferred getSubmissionFormParametersJavascript(String name, String[] parameterValues)
throws EngineException
{
assert name != null;
assert name.length() > 0;
assert parameterValues == null || parameterValues.length % 2 == 0;
mElementInfo.validateSubmissionName(name);
return _getSubmissionFormParametersJavascript(name, parameterValues, mOutputs.aggregateValues().entrySet());
}
private CharSequenceDeferred _getSubmissionFormParameters(String name, String[] parameterValues, Set<Map.Entry<String, String[]>> outputEntries)
throws EngineException
{
FlowState state = getSubmissionParameters(name, parameterValues, outputEntries);
return new CharSequenceFormState(mElementInfo.getStateStore(), state, FormStateType.PARAMS);
}
private CharSequenceDeferred _getSubmissionFormParametersJavascript(String name, String[] parameterValues, Set<Map.Entry<String, String[]>> outputEntries)
throws EngineException
{
FlowState state = getSubmissionParameters(name, parameterValues, outputEntries);
return new CharSequenceFormState(mElementInfo.getStateStore(), state, FormStateType.JAVASCRIPT);
}
void setSubmissionQuery(Template template, String name, String pathinfo, String[] parameterValues)
throws TemplateException, EngineException
{
template.setValue(PREFIX_SUBMISSION_QUERY+name, getSubmissionQueryUrl(name, pathinfo, parameterValues).encoder(EncoderHtml.getInstance()));
}
void setSubmissionForm(Template template, String name, String pathinfo, String[] parameterValues)
throws TemplateException, EngineException
{
template.setValue(PREFIX_SUBMISSION_FORM+name, getSubmissionFormUrl(pathinfo).encoder(EncoderHtml.getInstance()));
String submission_javascript = PREFIX_SUBMISSION_PARAMSJS+name;
if (template.hasValueId(submission_javascript))
{
template.setValue(submission_javascript, getSubmissionFormParametersJavascript(name, parameterValues));
}
else
{
template.setValue(PREFIX_SUBMISSION_PARAMS+name, getSubmissionFormParameters(name, parameterValues));
}
}
Collection<String> selectSubmissionParameter(Template template, String name, String[] values)
{
return selectParameter(template, PREFIX_PARAM+name, values);
}
void setSubmissionBean(Template template, Object beanInstance)
throws TemplateException, EngineException
{
setSubmissionBean(template, beanInstance, true);
}
void setSubmissionBean(Template template, Object beanInstance, boolean encode)
throws TemplateException, EngineException
{
template.setBean(beanInstance, PREFIX_PARAM, encode);
}
void removeSubmissionBean(Template template, Object beanInstance)
throws TemplateException, EngineException
{
template.removeBean(beanInstance, PREFIX_PARAM);
}
private <BeanType> BeanType _getSubmissionBean(Submission submission, Class<BeanType> beanClass, String prefix)
throws EngineException
{
assert submission != null;
assert beanClass != null;
BeanType bean_instance = getBeanInstance(beanClass);
try
{
HashMap<String, PropertyDescriptor> bean_properties = BeanUtils.getUppercasedBeanProperties(beanClass);
String[] parameter_values = null;
for (String parameter_name : submission.getParameterNames())
{
if (mElementState.hasRequestParameterValue(parameter_name))
{
parameter_values = mElementState.getRequestParameterValues(parameter_name);
if (parameter_values != null &&
parameter_values.length > 0)
{
BeanUtils.setUppercasedBeanProperty(parameter_name, parameter_values, prefix, bean_properties, bean_instance, null);
}
}
}
for (Pattern parameter_regexp : submission.getParameterRegexps())
{
for (String parameter_name : getParameterNames(parameter_regexp.pattern()))
{
if (mElementState.hasRequestParameterValue(parameter_name))
{
parameter_values = mElementState.getRequestParameterValues(parameter_name);
if (parameter_values != null &&
parameter_values.length > 0)
{
BeanUtils.setUppercasedBeanProperty(parameter_name, parameter_values, prefix, bean_properties, bean_instance, null);
}
}
}
}
for (String uploadedfile_name : getUploadedFileNames())
{
UploadedFile file = getUploadedFile(uploadedfile_name);
BeanUtils.setUppercasedBeanProperty(uploadedfile_name, file, prefix, bean_properties, bean_instance);
}
}
catch (BeanUtilsException e)
{
throw new EngineException(e);
}
return bean_instance;
}
<BeanType> BeanType getNamedSubmissionBean(String submissionName, String beanName)
throws EngineException
{
assert submissionName != null;
assert submissionName.length() > 0;
assert beanName != null;
assert beanName.length() > 0;
mElementInfo.validateSubmissionName(submissionName);
if (!hasSubmission(submissionName))
{
return null;
}
BeanDeclaration bean = mElementInfo.getSubmission(submissionName).getNamedBean(beanName);
Class<BeanType> bean_class = null;
try
{
bean_class = (Class<BeanType>)Class.forName(bean.getClassname());
}
catch (ClassNotFoundException e)
{
throw new NamedSubmissionBeanClassnameErrorException(mElementInfo.getDeclarationName(), submissionName, beanName, bean.getClassname(), e);
}
return _getSubmissionBean(mElementInfo.getSubmission(submissionName), bean_class, bean.getPrefix());
}
<BeanType> BeanType getSubmissionBean(String submissionName, Class<BeanType> beanClass, String prefix)
throws EngineException
{
assert submissionName != null;
assert submissionName.length() > 0;
assert beanClass != null;
mElementInfo.validateSubmissionName(submissionName);
if (!hasSubmission(submissionName))
{
return null;
}
return _getSubmissionBean(mElementInfo.getSubmission(submissionName), beanClass, prefix);
}
private void _fillSubmissionBean(Submission submission, Object bean, String prefix)
throws EngineException
{
assert submission != null;
if (null == bean)
{
return;
}
try
{
HashMap<String, PropertyDescriptor> bean_properties = BeanUtils.getUppercasedBeanProperties(bean.getClass());
String[] parameter_values = null;
Object empty_bean = null;
// handle regular parameters
for (String parameter_name : submission.getParameterNames())
{
parameter_values = mElementState.getRequestParameterValues(parameter_name);
if (null == empty_bean &&
(null == parameter_values ||
0 == parameter_values[0].length()))
{
try
{
empty_bean = bean.getClass().newInstance();
}
catch (InstantiationException e)
{
throw new EngineException("Unexpected error while invoking the default constructor of the bean with class '"+bean.getClass().getName()+"'.", e);
}
catch (IllegalAccessException e)
{
throw new EngineException("No permission to invoke the default constructor of the bean with class '"+bean.getClass().getName()+"'.", e);
}
}
BeanUtils.setUppercasedBeanProperty(parameter_name, parameter_values, prefix, bean_properties, bean, empty_bean);
}
// handle regexp parameters
for (Pattern parameter_regexp : submission.getParameterRegexps())
{
for (String parameter_name : getParameterNames(parameter_regexp.pattern()))
{
parameter_values = mElementState.getRequestParameterValues(parameter_name);
if (null == empty_bean &&
(null == parameter_values ||
0 == parameter_values[0].length()))
{
try
{
empty_bean = bean.getClass().newInstance();
}
catch (InstantiationException e)
{
throw new EngineException("Unexpected error while invoking the default constructor of the bean with class '"+bean.getClass().getName()+"'.", e);
}
catch (IllegalAccessException e)
{
throw new EngineException("No permission to invoke the default constructor of the bean with class '"+bean.getClass().getName()+"'.", e);
}
}
BeanUtils.setUppercasedBeanProperty(parameter_name, parameter_values, prefix, bean_properties, bean, empty_bean);
}
}
// automatically handle uploaded files
for (String uploadedfile_name : getUploadedFileNames())
{
UploadedFile file = getUploadedFile(uploadedfile_name);
BeanUtils.setUppercasedBeanProperty(uploadedfile_name, file, prefix, bean_properties, bean);
}
}
catch (BeanUtilsException e)
{
throw new EngineException(e);
}
}
void fillSubmissionBean(String submissionName, Object bean, String prefix)
throws EngineException
{
assert submissionName != null;
assert submissionName.length() > 0;
if (null == bean)
{
return;
}
mElementInfo.validateSubmissionName(submissionName);
if (!hasSubmission(submissionName))
{
return;
}
_fillSubmissionBean(mElementInfo.getSubmission(submissionName), bean, prefix);
}
<BeanType> BeanType getNamedInputBean(String name)
throws EngineException
{
assert name != null;
mElementInfo.validateInbeanName(name);
BeanDeclaration input_bean = mElementInfo.getNamedInbeanInfo(name);
if (null == input_bean)
{
input_bean = mElementInfo.getNamedGlobalBeanInfo(name);
}
Class<BeanType> input_bean_class = null;
try
{
input_bean_class = (Class<BeanType>)Class.forName(input_bean.getClassname());
}
catch (ClassNotFoundException e)
{
throw new NamedInbeanClassnameErrorException(mElementInfo.getDeclarationName(),name, input_bean.getClassname());
}
return getInputBean(input_bean_class, input_bean.getPrefix());
}
<BeanType> BeanType getInputBean(Class<BeanType> beanClass, String prefix)
throws EngineException
{
assert beanClass != null;
BeanType bean_instance = getBeanInstance(beanClass);
try
{
HashMap<String, PropertyDescriptor> bean_properties = BeanUtils.getUppercasedBeanProperties(beanClass);
// merge the input and global variable names
Collection<String> input_names = mElementInfo.getInputNames();
Collection<String> globalvar_names = mElementInfo.getGlobalVarNames();
ArrayList<String> merged_names = new ArrayList<String>();
merged_names.addAll(input_names);
merged_names.addAll(globalvar_names);
// process all the possible input names
String[] values = null;
for (String name : merged_names)
{
if (mElementState.hasInputValue(name))
{
values = mElementState.getInputValues(name);
if (values != null &&
values.length > 0)
{
BeanUtils.setUppercasedBeanProperty(name, values, prefix, bean_properties, bean_instance, null);
}
}
}
}
catch (BeanUtilsException e)
{
throw new EngineException(e);
}
return bean_instance;
}
void setNamedOutputBean(String name, Object bean)
throws EngineException
{
assert name != null;
mElementInfo.validateOutbeanName(name);
BeanDeclaration output_bean = mElementInfo.getNamedOutbeanInfo(name);
if (null == output_bean)
{
output_bean = mElementInfo.getNamedGlobalBeanInfo(name);
}
setOutputBean(bean, output_bean.getPrefix());
}
void setOutputBean(Object bean, String prefix)
throws EngineException
{
if (null == bean) throw new IllegalArgumentException("bean can't be null.");
Map<String, String[]> values = getOutputBeanValues(bean, prefix, null);
String name;
String[] value;
for (Map.Entry<String, String[]> entry : values.entrySet())
{
name = entry.getKey();
value = entry.getValue();
setOutputValues(name, value);
if (mElementState.inInheritanceStructure() &&
mElementInfo.containsChildTrigger(name))
{
triggerChild(name, value);
}
}
}
Map<String, String[]> getOutputBeanValues(Object bean, String prefix, Collection<String> included)
throws BeanInstanceValuesErrorException
{
if (null == bean) return Collections.EMPTY_MAP;
Map<String, String[]> values = new LinkedHashMap<String, String[]>();
try
{
Constrained constrained = ConstrainedUtils.makeConstrainedInstance(bean);
ConstrainedProperty constrained_property = null;
Set<String> merged_names = new LinkedHashSet<String>();
// handle outputs
Collection<String> output_names = mElementInfo.getOutputNames();
if (null == included)
{
merged_names.addAll(output_names);
}
else
{
for (String name : output_names)
{
if (included.contains(name))
{
merged_names.add(name);
}
}
}
// handle globals
Collection<String> globalvar_names = mElementInfo.getGlobalVarNames();
if (null == included)
{
merged_names.addAll(globalvar_names);
}
else
{
for (String name : globalvar_names)
{
if (included.contains(name))
{
merged_names.add(name);
}
}
}
// create the merged array
String[] merged_names_array = new String[merged_names.size()];
merged_names.toArray(merged_names_array);
// process all the possible output names
Map<String, Object> property_values = BeanUtils.getPropertyValues(bean, merged_names_array, null, prefix);
Object property_value = null;
for (String property_name : property_values.keySet())
{
property_value = property_values.get(property_name);
if (property_value != null)
{
// get the constrained property if that's appropriate
if (constrained != null)
{
if (prefix != null)
{
constrained_property = constrained.getConstrainedProperty(property_name.substring(prefix.length()));
}
else
{
constrained_property = constrained.getConstrainedProperty(property_name);
}
}
values.put(property_name, getOutputObjectValues(property_name, property_value, constrained_property));
}
}
}
catch (BeanUtilsException e)
{
throw new BeanInstanceValuesErrorException(bean, e);
}
return values;
}
private <BeanType> BeanType getBeanInstance(Class<BeanType> beanClass)
throws EngineException
{
BeanType bean_instance;
try
{
bean_instance = beanClass.newInstance();
}
catch (InstantiationException e)
{
throw new EngineException("Can't instantiate a bean with class '"+beanClass.getName()+"'.", e);
}
catch (IllegalAccessException e)
{
throw new EngineException("No permission to instantiate a bean with class '"+beanClass.getName()+"'.", e);
}
return bean_instance;
}
void processEmbeddedElement(Template template, ElementSupport embeddingElement, String elementId, String differentiator, Object data)
throws TemplateException, EngineException
{
// process the embedded elements
if (template.hasFilteredValues(TAG_ELEMENT))
{
List<String[]> element_tags = template.getFilteredValues(TAG_ELEMENT);
for (String[] captured_groups : element_tags)
{
if (null == differentiator)
{
if (elementId.equals(captured_groups[3]))
{
processEmbeddedElement(captured_groups[0], template, embeddingElement, captured_groups[3], null, data);
return;
}
}
else
{
if (elementId.equals(captured_groups[3]))
{
String value_id = captured_groups[1]+":";
String differentiator_value_id = value_id+differentiator;
if (template.hasValueId(differentiator_value_id))
{
processEmbeddedElement(differentiator_value_id, template, embeddingElement, elementId, differentiator, data);
return;
}
else if (template.hasValueId(value_id))
{
processEmbeddedElement(value_id, template, embeddingElement, elementId, differentiator, data);
return;
}
}
}
}
}
throw new EmbeddedElementNotFoundException(elementId);
}
private void processEmbeddedElement(String valueId, Template template, ElementSupport embeddingElement, String elementId, String differentiator, Object data)
throws TemplateException, EngineException
{
if (!template.hasValueId(valueId))
{
throw new EmbeddedElementNotFoundException(elementId);
}
ElementInfo embedded_element = null;
RequestState embedded_state = null;
Response embedded_response = null;
// try to obtain the embedded element and throw an exception if
// it couldn't be found
embedded_element = mElementInfo.getSite().resolveId(elementId, mElementInfo);
if (null == embedded_element)
{
throw new ElementIdNotFoundException(elementId);
}
// build the embedded element request parameter by merging
// the current element's request parameters with its input values
// also merge in the state global vars
Map<String, String[]> parameters = new HashMap<String, String[]>(mElementState.getRequestParameters());
for (Map.Entry<String, String[]> input_entry : mElementState.getInputEntries())
{
if (!parameters.containsKey(input_entry.getKey()))
{
parameters.put(input_entry.getKey(), input_entry.getValue());
}
}
if (mRequestState.getStateGlobalVars() != null)
{
for (Map.Entry<String, String[]> globalvar_entry : mRequestState.getStateGlobalVars().entrySet())
{
parameters.put(globalvar_entry.getKey(), globalvar_entry.getValue());
}
}
// build the request and response objects for the embedded element
// and service the request
EmbeddingContext embedding_context = new EmbeddingContext(this, embeddingElement, template, template.getDefaultValue(valueId), differentiator, data);
embedded_response = mResponse.createEmbeddedResponse(valueId, differentiator);
embedded_state = RequestState.getEmbeddedInstance(embedded_response, embedding_context, parameters, embedded_element);
embedded_state.service();
embedded_response.close();
if (embedding_context.getCancelEmbedding())
{
// handle embedding cancellation by throwing a dedicated exception
// that will bubble up to the first embedding element and print
// out the embedded content
throw new CancelEmbeddingTriggeredException(embedded_response.getEmbeddedContent());
}
else
{
// set the output of the element to the value in the template
template.setValue(valueId, embedded_response.getEmbeddedContent());
}
}
void evaluateExpressionRoleUserTags(List<String> setValues, Template template, String id)
{
if (template.hasFilteredBlocks(TAG_OGNL_ROLEUSER) ||
template.hasFilteredBlocks(TAG_MVEL_ROLEUSER) ||
template.hasFilteredBlocks(TAG_GROOVY_ROLEUSER) ||
template.hasFilteredBlocks(TAG_JANINO_ROLEUSER))
{
RoleUserIdentity identity = (RoleUserIdentity)mRequestState.getRequestAttribute(Identified.IDENTITY_ATTRIBUTE_NAME);
if (identity != null)
{
RoleUserAttributes attributes = identity.getAttributes();
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("login", identity.getLogin());
map.put("password", attributes.getPassword());
map.put("userId", attributes.getUserId());
map.put("roles", attributes.getRoles());
if (template.hasFilteredBlocks(TAG_OGNL_ROLEUSER))
{
String language_id = id;
if (language_id != null)
{
language_id = PREFIX_OGNL_ROLEUSER+language_id;
}
FilteredTagProcessorOgnl.getInstance().processTags(setValues, template, template.getFilteredBlocks(TAG_OGNL_ROLEUSER), language_id, RoleUserAttributes.class, "user", attributes, map);
}
if (template.hasFilteredBlocks(TAG_MVEL_ROLEUSER))
{
String language_id = id;
if (language_id != null)
{
language_id = PREFIX_MVEL_ROLEUSER+language_id;
}
FilteredTagProcessorMvel.getInstance().processTags(setValues, template, template.getFilteredBlocks(TAG_MVEL_ROLEUSER), language_id, RoleUserAttributes.class, "user", attributes, map);
}
if (template.hasFilteredBlocks(TAG_GROOVY_ROLEUSER))
{
String language_id = id;
if (language_id != null)
{
language_id = PREFIX_GROOVY_ROLEUSER+language_id;
}
FilteredTagProcessorGroovy.getInstance().processTags(setValues, template, template.getFilteredBlocks(TAG_GROOVY_ROLEUSER), language_id, RoleUserAttributes.class, "user", attributes, map);
}
if (template.hasFilteredBlocks(TAG_JANINO_ROLEUSER))
{
String language_id = id;
if (language_id != null)
{
language_id = PREFIX_JANINO_ROLEUSER+language_id;
}
FilteredTagProcessorJanino.getInstance().processTags(setValues, template, template.getFilteredBlocks(TAG_JANINO_ROLEUSER), language_id, RoleUserAttributes.class, "user", attributes, map);
}
}
}
}
private String getEncodedChildRequest()
{
String child_request = null;
if (mElementState.hasRequestParameterValue(ReservedParameters.CHILDREQUEST))
{
child_request = mElementState.getRequestParameter(ReservedParameters.CHILDREQUEST);
}
else
{
child_request = ChildRequestEncoder.encode(mElementState.getInheritanceStack().get(0), mRequestState);
}
return child_request;
}
}
|