0001: /*
0002: * Copyright 2001-2007 Geert Bevin <gbevin[remove] at uwyn dot com>
0003: * Distributed under the terms of either:
0004: * - the common development and distribution license (CDDL), v1.0; or
0005: * - the GNU Lesser General Public License, v2.1 or later
0006: * $Id: ElementContext.java 3813 2007-06-25 18:22:03Z gbevin $
0007: */
0008: package com.uwyn.rife.engine;
0009:
0010: import com.uwyn.rife.engine.exceptions.*;
0011: import com.uwyn.rife.template.*;
0012: import com.uwyn.rife.tools.*;
0013: import java.util.*;
0014:
0015: import com.uwyn.rife.authentication.credentialsmanagers.RoleUserAttributes;
0016: import com.uwyn.rife.authentication.credentialsmanagers.RoleUserIdentity;
0017: import com.uwyn.rife.authentication.elements.Identified;
0018: import com.uwyn.rife.config.RifeConfig;
0019: import com.uwyn.rife.continuations.CallState;
0020: import com.uwyn.rife.continuations.ContinuationConfigRuntime;
0021: import com.uwyn.rife.continuations.ContinuationContext;
0022: import com.uwyn.rife.continuations.ContinuationManager;
0023: import com.uwyn.rife.continuations.exceptions.AnswerException;
0024: import com.uwyn.rife.continuations.exceptions.CallException;
0025: import com.uwyn.rife.continuations.exceptions.PauseException;
0026: import com.uwyn.rife.continuations.exceptions.StepBackException;
0027: import com.uwyn.rife.engine.CharSequenceDeferred;
0028: import com.uwyn.rife.site.Constrained;
0029: import com.uwyn.rife.site.ConstrainedProperty;
0030: import com.uwyn.rife.site.ConstrainedUtils;
0031: import com.uwyn.rife.site.FormBuilder;
0032: import com.uwyn.rife.template.exceptions.TemplateException;
0033: import com.uwyn.rife.tools.exceptions.BeanUtilsException;
0034: import com.uwyn.rife.tools.exceptions.LightweightError;
0035: import com.uwyn.rife.tools.exceptions.SerializationUtilsErrorException;
0036: import java.beans.PropertyDescriptor;
0037: import java.io.IOException;
0038: import java.io.Serializable;
0039: import java.io.UnsupportedEncodingException;
0040: import java.lang.reflect.InvocationTargetException;
0041: import java.lang.reflect.Method;
0042: import java.util.regex.Matcher;
0043: import java.util.regex.Pattern;
0044: import javax.servlet.RequestDispatcher;
0045: import javax.servlet.http.Cookie;
0046: import javax.servlet.http.HttpServletResponse;
0047:
0048: public class ElementContext {
0049: public static final String PREFIX_EXIT_QUERY = "EXIT:QUERY:";
0050: public static final String PREFIX_EXIT_FORM = "EXIT:FORM:";
0051: public static final String PREFIX_EXIT_PARAMS = "EXIT:PARAMS:";
0052: public static final String PREFIX_EXIT_PARAMSJS = "EXIT:PARAMSJS:";
0053: public static final String PREFIX_SUBMISSION_QUERY = "SUBMISSION:QUERY:";
0054: public static final String PREFIX_SUBMISSION_FORM = "SUBMISSION:FORM:";
0055: public static final String PREFIX_SUBMISSION_PARAMS = "SUBMISSION:PARAMS:";
0056: public static final String PREFIX_SUBMISSION_PARAMSJS = "SUBMISSION:PARAMSJS:";
0057:
0058: public static final String PREFIX_PARAM = "PARAM:";
0059: public static final String PREFIX_INPUT = "INPUT:";
0060: public static final String PREFIX_OUTPUT = "OUTPUT:";
0061: public static final String PREFIX_INCOOKIE = "INCOOKIE:";
0062: public static final String PREFIX_OUTCOOKIE = "OUTCOOKIE:";
0063: public static final String PREFIX_ELEMENT = "ELEMENT:";
0064: public static final String PREFIX_PROPERTY = "PROPERTY:";
0065: public static final String PREFIX_OGNL_ROLEUSER = "OGNL:ROLEUSER:";
0066: public static final String PREFIX_MVEL_ROLEUSER = "MVEL:ROLEUSER:";
0067: public static final String PREFIX_GROOVY_ROLEUSER = "GROOVY:ROLEUSER:";
0068: public static final String PREFIX_JANINO_ROLEUSER = "JANINO:ROLEUSER:";
0069:
0070: public static final String ID_WEBAPP_ROOTURL = "WEBAPP:ROOTURL";
0071: public static final String ID_SERVER_ROOTURL = "SERVER:ROOTURL";
0072:
0073: public static final String TAG_PROPERTY = "^" + PREFIX_PROPERTY
0074: + "\\s*(.*?)\\s*$";
0075: public static final String TAG_ELEMENT = "^(" + PREFIX_ELEMENT
0076: + "\\s*([\\-\\+]?)\\s*(.*?)\\s*)(?::([^:]*))?$";
0077: public static final String TAG_OGNL_ROLEUSER = "(?s)^("
0078: + PREFIX_OGNL_ROLEUSER
0079: + ".*):\\s*\\[\\[\\s*+(.*?)\\s*+\\]\\]\\s*$";
0080: public static final String TAG_MVEL_ROLEUSER = "(?s)^("
0081: + PREFIX_MVEL_ROLEUSER
0082: + ".*):\\s*\\[\\[\\s*+(.*?)\\s*+\\]\\]\\s*$";
0083: public static final String TAG_JANINO_ROLEUSER = "(?s)^("
0084: + PREFIX_JANINO_ROLEUSER
0085: + ".*):\\s*\\[\\[\\s*+(.*?)\\s*+\\]\\]\\s*$";
0086: public static final String TAG_GROOVY_ROLEUSER = "(?s)^("
0087: + PREFIX_GROOVY_ROLEUSER
0088: + ".*):\\s*\\[\\[\\s*+(.*?)\\s*+\\]\\]\\s*$";
0089:
0090: private static ThreadLocal<ElementSupport> sActiveElementSupport = new ThreadLocal<ElementSupport>();
0091:
0092: private ElementSupport mElement = null;
0093: private ElementInfo mElementInfo = null;
0094: private RequestState mRequestState = null;
0095: private ElementExecutionState mElementState = null;
0096: private Response mResponse = null;
0097: private OutputValues mOutputs = null;
0098: private OutcookieValues mOutcookies = null;
0099: private ArrayList<OutputListener> mOutputListeners = null;
0100: private ArrayList<OutcookieListener> mOutcookieListeners = null;
0101: private String mContextId = null;
0102: private String mSubmission = null;
0103: private boolean mSteppedBack = false;
0104:
0105: public static ElementSupport getActiveElementSupport() {
0106: return sActiveElementSupport.get();
0107: }
0108:
0109: ElementContext(ElementSupport element, RequestState state,
0110: Response response) throws EngineException {
0111: assert element != null;
0112: assert state != null;
0113: assert response != null;
0114:
0115: mElement = element;
0116: synchronized (mElement) {
0117: mElement.setElementContext(this );
0118:
0119: mElementInfo = mElement.getElementInfo();
0120:
0121: mRequestState = state;
0122: mElementState = mRequestState.getElementState();
0123: mResponse = response;
0124: mOutputs = new OutputValues(this );
0125: mOutcookies = new OutcookieValues(this );
0126:
0127: // register the EmbeddingListener of the current state so that the
0128: // output values are kept in sync with global vars and the outcookies
0129: // are kept in sync with the global cookies
0130: if (state.isEmbedded()) {
0131: RequestState.EmbeddingListener listener = state
0132: .getEmbeddingListener();
0133: addOutputListener(listener);
0134: addOutcookieListener(listener);
0135: }
0136:
0137: // register the PrecedenceListener of the current state so that the
0138: // output values are kept in sync with global vars and the outcookies
0139: // are kept in sync with the global cookies
0140: if (state.isPreceeding()) {
0141: RequestState.PrecedenceListener listener = state
0142: .getPrecedenceListener();
0143: addOutputListener(listener);
0144: addOutcookieListener(listener);
0145: }
0146:
0147: // if the child element has been reached, replace the request parameters with the
0148: // original child request parameters
0149: if (mElementState.isInheritanceTarget()
0150: && mElementState
0151: .hasRequestParameterValue(ReservedParameters.CHILDREQUEST)) {
0152: ChildRequestEncoder.decode(element.getElementInfo(),
0153: mRequestState);
0154: }
0155:
0156: // automatically set an output value if the input value has been provided
0157: // and it's a global variable
0158: String[] output_values = null;
0159: for (String globalvar_name : mElementInfo
0160: .getGlobalVarNames()) {
0161: if (mElementState.hasInputValue(globalvar_name)) {
0162: output_values = mElementState
0163: .getInputValues(globalvar_name);
0164: setAutomatedOutputValues(globalvar_name,
0165: output_values);
0166: }
0167: }
0168: }
0169: }
0170:
0171: private void handleChildTriggerVariablesPre()
0172: throws EngineException {
0173: // verify if no value are present that will automatically launch a child trigger
0174: if (mElementInfo.getChildTriggerNames().size() > 0) {
0175: // check each child trigger for a corresponding value
0176: // if it was found, launch the trigger
0177: for (String child_trigger_name : mElementInfo
0178: .getChildTriggerNames()) {
0179: // check if a provided input value is acceptable for this
0180: // element as input or global variable
0181: if (mElementState.hasInputValue(child_trigger_name)) {
0182: if (mElementInfo
0183: .containsGlobalVar(child_trigger_name)
0184: || mElementInfo
0185: .containsInput(child_trigger_name)) {
0186: triggerChild(child_trigger_name,
0187: getInputValues(child_trigger_name));
0188: continue;
0189: }
0190: }
0191: // check if a provided cookie is acceptable for this
0192: // element as incookie
0193: else if (mRequestState.getCookie(child_trigger_name) != null) {
0194: if (mElementInfo
0195: .containsGlobalCookie(child_trigger_name)
0196: || mElementInfo
0197: .containsIncookie(child_trigger_name)) {
0198: triggerChild(
0199: child_trigger_name,
0200: new String[] { getCookie(
0201: child_trigger_name).getValue() });
0202: continue;
0203: }
0204: }
0205: // check if a default input value is present that can trigger the child
0206: else if (mElementInfo
0207: .hasInputDefaultValues(child_trigger_name)) {
0208: triggerChild(child_trigger_name, mElementInfo
0209: .getInputDefaultValues(child_trigger_name));
0210: continue;
0211: }
0212: // check if a default cookie value is present that can trigger the child
0213: else if (mElementInfo
0214: .hasIncookieDefaultValue(child_trigger_name)) {
0215: triggerChild(
0216: child_trigger_name,
0217: new String[] { mElementInfo
0218: .getIncookieDefaultValue(child_trigger_name) });
0219: continue;
0220: }
0221: // check if a global var default is present for the trigger name
0222: else if (mElementInfo
0223: .containsGlobalVar(child_trigger_name)
0224: && mElementInfo
0225: .hasGlobalVarDefaultValues(child_trigger_name)) {
0226: triggerChild(
0227: child_trigger_name,
0228: mElementInfo
0229: .getGlobalVarDefaultValues(child_trigger_name));
0230: continue;
0231: }
0232: // check if a global cookie default is present for the trigger name
0233: else if (mElementInfo
0234: .containsGlobalCookie(child_trigger_name)
0235: && mElementInfo
0236: .hasGlobalCookieDefaultValue(child_trigger_name)) {
0237: triggerChild(
0238: child_trigger_name,
0239: new String[] { mElementInfo
0240: .getGlobalCookieDefaultValue(child_trigger_name) });
0241: continue;
0242: }
0243: }
0244: }
0245: }
0246:
0247: private void handleChildTriggerVariablesPost()
0248: throws EngineException {
0249: // verify if no value are present that will automatically launch a child trigger
0250: if (mElementInfo.getChildTriggerNames().size() > 0) {
0251: // check each child trigger for a corresponding value
0252: // if it was found, launch the trigger
0253: for (String child_trigger_name : mElementInfo
0254: .getChildTriggerNames()) {
0255: // check if an output default value is present
0256: if (mElementInfo
0257: .hasOutputDefaultValues(child_trigger_name)) {
0258: String[] output_defaultvalues = mElementInfo
0259: .getOutputDefaultValues(child_trigger_name);
0260: triggerChild(child_trigger_name,
0261: output_defaultvalues);
0262: continue;
0263: }
0264: }
0265: }
0266: }
0267:
0268: ElementContext processContext() throws EngineException {
0269: long start = mElementInfo.startTrace();
0270: boolean clear_request = false;
0271:
0272: ElementContext result = null;
0273:
0274: try {
0275: ElementSupport previous_active_element;
0276:
0277: synchronized (mElement) {
0278: // handle the inheritance structure
0279: if (mElementState.inInheritanceStructure()) {
0280: // try to see if the top of the trigger list matches the current element
0281: if (mElementState.isNextTrigger(mElementInfo)) {
0282: // if it does, and it's a child trigger, use the values to launch a child trigger
0283: if (TriggerContext.TRIGGER_CHILD == mElementState
0284: .getNextTriggerType()
0285: && mElementInfo
0286: .containsChildTrigger(mElementState
0287: .getNextTriggerName())) {
0288: triggerChild(mElementState
0289: .getNextTriggerName(),
0290: mElementState
0291: .getNextTriggerValues());
0292: } else if (TriggerContext.TRIGGER_EXIT == mElementState
0293: .getNextTriggerType()
0294: && mElementInfo
0295: .containsExit(mElementState
0296: .getNextTriggerName())) {
0297: exit(mElementState.getNextTriggerName());
0298: }
0299: }
0300:
0301: handleChildTriggerVariablesPre();
0302: }
0303:
0304: // handle precedence
0305: mRequestState.handlePrecedence(mResponse,
0306: getElementInfo());
0307:
0308: // set the response content type if this has been specified by the element
0309: if (mElementInfo.getContentType() != null
0310: && mElementInfo.getContentType().length() > 0) {
0311: mResponse.setContentType(mElementInfo
0312: .getContentType());
0313: }
0314:
0315: // obtain the continuation context
0316: ContinuationContext continuation_context = mRequestState
0317: .getContinuationContext(mElementInfo);
0318: ContinuationContext
0319: .setActiveContext(continuation_context);
0320: ContinuationConfigRuntime
0321: .setActiveConfigRuntime(EngineContinuationConfigRuntimeSingleton.INSTANCE);
0322:
0323: // register the element as the active one in this thread and remember
0324: // which one that was previously active
0325: previous_active_element = sActiveElementSupport.get();
0326:
0327: sActiveElementSupport.set(mElement);
0328: }
0329:
0330: try {
0331: final ElementAware element_aware;
0332: Method submission_handler = null;
0333:
0334: synchronized (mElement) {
0335: // get the element aware interface
0336: element_aware = mElement.getElementAware();
0337:
0338: // check if there's are submissions
0339: if (mElementState
0340: .hasRequestParameterValue(ReservedParameters.SUBMISSION)) {
0341: String[] submission_names = mElementState
0342: .getRequestParameterValues(ReservedParameters.SUBMISSION);
0343: String[] submission_contexts = mElementState
0344: .getRequestParameterValues(ReservedParameters.SUBMISSIONCONTEXT);
0345: String submission_context = null;
0346: String submission_context_id = null;
0347: String submission_target = null;
0348: HashSet<String> non_requestparameter_inputs = null;
0349: int counter = 0;
0350: for (String submission_name : submission_names) {
0351: // get the submission context
0352: if (null == submission_contexts
0353: || counter >= submission_contexts.length) {
0354: submission_context = getContextId();
0355: } else {
0356: try {
0357: byte[] decoded = Base64
0358: .decode(submission_contexts[counter]
0359: .getBytes("UTF-8"));
0360: if (decoded != null
0361: && decoded.length > 0) {
0362: submission_context = new String(
0363: decoded);
0364: } else {
0365: submission_context = getContextId();
0366: }
0367: } catch (UnsupportedEncodingException e) {
0368: // should never happen
0369: }
0370: }
0371:
0372: // split up in the submission context id and the submission target
0373: int seperator_index = submission_context
0374: .indexOf("^");
0375: if (-1 == seperator_index) {
0376: submission_context_id = submission_context;
0377: submission_target = submission_context;
0378: } else {
0379: submission_context_id = submission_context
0380: .substring(0, seperator_index);
0381: submission_target = submission_context
0382: .substring(seperator_index + 1);
0383: }
0384:
0385: // check if the submission target corresponds to the context id
0386: if (null == mSubmission
0387: && getContextId().equals(
0388: submission_context_id)
0389: && mElementInfo
0390: .hasSubmission(submission_name)) {
0391: mSubmission = submission_name;
0392: }
0393: // if it doesn't, use the submission target element id to
0394: // retrieve the submission declaration, and the parameters
0395: // that have to be disabled as inputs for this element
0396: else {
0397: // get the submission target
0398: if (0 == submission_target.length()) {
0399: submission_target = getElementInfo()
0400: .getId();
0401: }
0402:
0403: // obtain the element info
0404: ElementInfo submission_target_element = mElementInfo
0405: .getSite().resolveId(
0406: submission_target);
0407: if (submission_target_element != null) {
0408: // get the submission declaration
0409: Submission submission = submission_target_element
0410: .getSubmission(submission_name);
0411: if (submission != null) {
0412: // get the submission parameter names
0413: Collection<String> names = submission
0414: .getParameterNames();
0415: if (names != null
0416: && names.size() > 0) {
0417: if (null == non_requestparameter_inputs) {
0418: non_requestparameter_inputs = new HashSet<String>();
0419: }
0420:
0421: // add the submission parameters to the collection
0422: // of inputs that shouldn't retrieve their values
0423: // from the request parameters
0424: non_requestparameter_inputs
0425: .addAll(names);
0426: }
0427: }
0428: }
0429: }
0430:
0431: counter++;
0432: }
0433:
0434: // register the non parameter inputs
0435: mElementState
0436: .setNonRequestParameterInputs(non_requestparameter_inputs);
0437: }
0438:
0439: // check if there's a submission handler
0440:
0441: // check if a submission is present and a corresponding do*() method is
0442: // available and retrieve the method
0443: final String submission_name = getSubmission();
0444: if (submission_name != null) {
0445: String submission_handler_name = "do"
0446: + StringUtils
0447: .capitalize(submission_name);
0448: try {
0449: submission_handler = element_aware
0450: .getClass().getMethod(
0451: submission_handler_name,
0452: (Class[]) null);
0453: submission_handler.setAccessible(true);
0454: } catch (NoSuchMethodException e) {
0455: submission_handler = null;
0456: } catch (SecurityException e) {
0457: throw new EngineException(e);
0458: }
0459: }
0460:
0461: // inject the properties request values into the element instance
0462: new ElementInjector(this )
0463: .performInjection(submission_name);
0464:
0465: // update the target element in the response
0466: mResponse.setLastElement(mElement);
0467:
0468: // initialize the element in a fully setup context
0469: mElement.initialize();
0470: }
0471:
0472: try {
0473: try {
0474: synchronized (mElement) {
0475: // call the processElement() method of the element itself if no handler could be found
0476: if (null == submission_handler) {
0477: element_aware.processElement();
0478: }
0479: // call the submission handler if it's available
0480: else {
0481: try {
0482: submission_handler.invoke(
0483: element_aware,
0484: (Object[]) null);
0485: } catch (InvocationTargetException e) {
0486: if (e.getCause() instanceof LightweightError) {
0487: throw (LightweightError) e
0488: .getCause();
0489: } else if (e.getCause() instanceof EngineException) {
0490: throw (EngineException) e
0491: .getCause();
0492: } else {
0493: throw new EngineException(e
0494: .getCause());
0495: }
0496: } catch (IllegalArgumentException e) {
0497: throw new EngineException(e);
0498: } catch (IllegalAccessException e) {
0499: throw new EngineException(e);
0500: }
0501: }
0502: }
0503: } catch (CallException e) {
0504: ContinuationContext context = e.getContext();
0505:
0506: // register context
0507: ContinuationManager manager = mElementInfo
0508: .getSite().getContinuationManager();
0509: manager.addContext(context);
0510:
0511: synchronized (mElement) {
0512: String exit = (String) e.getTarget();
0513: mElementInfo.validateExitName(exit);
0514: if (null == mElementInfo.getFlowLink(exit)) {
0515: throw new ExitNotAttachedException(
0516: mElementInfo
0517: .getDeclarationName(),
0518: exit);
0519: }
0520:
0521: // create a new call state
0522: CallState call_state = new CallState(
0523: context.getId(), mElementState
0524: .clone());
0525: context.setCreatedCallState(call_state);
0526:
0527: // setup the exit
0528: result = setupExitContext(exit);
0529: }
0530: }
0531: } finally {
0532: synchronized (mElement) {
0533: String context_id = getContextId();
0534:
0535: ElementResultState result_state = null;
0536:
0537: // extract the preserved inputs of this element
0538: Set<Map.Entry<String, String[]>> output_value_entries = mOutputs
0539: .aggregateValues().entrySet();
0540: Map<String, String[]> preserved_inputs = collectPreservedInputs(output_value_entries);
0541:
0542: // if a call continuation is active, also preserve the previous preserved inputs without overriding the new ones
0543: ContinuationContext active_context = ContinuationContext
0544: .getActiveContext();
0545: if (active_context != null
0546: && active_context.getActiveCallState() != null) {
0547: ElementResultState previous_result_state = mRequestState
0548: .getElementResultStatesRestored()
0549: .get(context_id);
0550: if (previous_result_state != null) {
0551: Map<String, String[]> previous_preserved_inputs = previous_result_state
0552: .getPreservedInputs();
0553: if (previous_preserved_inputs != null) {
0554: if (null == preserved_inputs) {
0555: preserved_inputs = previous_preserved_inputs;
0556: } else {
0557: for (Map.Entry<String, String[]> entry : previous_preserved_inputs
0558: .entrySet()) {
0559: if (!preserved_inputs
0560: .containsKey(entry
0561: .getKey())) {
0562: preserved_inputs
0563: .put(
0564: entry
0565: .getKey(),
0566: entry
0567: .getValue());
0568: }
0569: }
0570: }
0571: }
0572: }
0573:
0574: // preserve the continuation ID of this element
0575: if (null == result_state) {
0576: result_state = mElementInfo
0577: .getStateStore()
0578: .createNewResultState(
0579: context_id);
0580: }
0581: result_state
0582: .setContinuationId(active_context
0583: .getActiveCallState()
0584: .getContinuationId());
0585: }
0586:
0587: // add the preserved inputs to the result state
0588: if (preserved_inputs != null
0589: && preserved_inputs.size() > 0) {
0590: if (null == result_state) {
0591: result_state = mElementInfo
0592: .getStateStore()
0593: .createNewResultState(
0594: context_id);
0595: }
0596:
0597: result_state
0598: .setPreservedInputs(preserved_inputs);
0599: }
0600:
0601: // state the resulting element state
0602: if (result_state != null) {
0603: mRequestState
0604: .getElementResultStatesObtained()
0605: .put(result_state);
0606: }
0607:
0608: // handle the setting of the getter outcookies
0609: mOutcookies.processGetters();
0610:
0611: // handle the firing of listener methods for getters outjection
0612: mOutputs.processGetters();
0613: }
0614:
0615: // handle the outcookie and output childtriggers from the getters outjection
0616: mOutcookies.processGetterChildTriggers();
0617: mOutputs.processGetterChildTriggers();
0618: }
0619: } catch (AnswerException e) {
0620: synchronized (mElement) {
0621: // only answer a call if a call state is available
0622: // otherwise the answer will function as a regular return
0623: if (e.getContext().getActiveCallState() != null) {
0624: throw e;
0625: }
0626: }
0627: } finally {
0628: synchronized (mElement) {
0629: // restore the previously active element
0630: sActiveElementSupport.set(previous_active_element);
0631: }
0632: }
0633:
0634: synchronized (mElement) {
0635: // handle the child trigger values that could have an effect after
0636: // the actual element logic
0637: handleChildTriggerVariablesPost();
0638:
0639: // handle the default outcookies
0640: if (mElementInfo.hasOutcookieDefaults()) {
0641: Cookie default_cookie = null;
0642:
0643: for (Map.Entry<String, String> default_outcookie_entry : mElementInfo
0644: .getDefaultOutcookies().entrySet()) {
0645: if (!mOutcookies
0646: .contains(default_outcookie_entry
0647: .getKey())) {
0648: default_cookie = new Cookie(
0649: default_outcookie_entry.getKey(),
0650: default_outcookie_entry.getValue());
0651: default_cookie.setPath("");
0652: setCookie(default_cookie);
0653: }
0654: }
0655: }
0656:
0657: // handle the default global cookies
0658: if (mElementInfo.hasGlobalCookieDefaults()) {
0659: Cookie default_cookie = null;
0660:
0661: for (Map.Entry<String, String> default_globalcookie_entry : mElementInfo
0662: .getDefaultGlobalCookies().entrySet()) {
0663: if (!mOutcookies
0664: .contains(default_globalcookie_entry
0665: .getKey())) {
0666: default_cookie = new Cookie(
0667: default_globalcookie_entry.getKey(),
0668: default_globalcookie_entry
0669: .getValue());
0670: default_cookie.setPath("");
0671: setCookie(default_cookie);
0672: }
0673: }
0674: }
0675: }
0676: } catch (PauseException e) {
0677: ContinuationContext context = e.getContext();
0678:
0679: // register context
0680: ContinuationManager manager = mElementInfo.getSite()
0681: .getContinuationManager();
0682: manager.addContext(context);
0683:
0684: synchronized (mElement) {
0685: // preserve the continuation ID of this element
0686: String context_id = getContextId();
0687: ElementResultState result_state = mRequestState
0688: .getElementResultStatesObtained().get(
0689: context_id);
0690:
0691: if (null == result_state) {
0692: result_state = mElementInfo.getStateStore()
0693: .createNewResultState(context_id);
0694: mRequestState.getElementResultStatesObtained().put(
0695: result_state);
0696: }
0697: result_state.setContinuationId(context.getId());
0698:
0699: clear_request = true;
0700: try {
0701: mResponse.flush();
0702: } catch (EngineException e2) {
0703: // if errors occurred during flushing it means that the client has
0704: // disconnected, disregard them
0705: }
0706: mResponse = null;
0707: }
0708: } catch (ChildTriggeredException e) {
0709: synchronized (mElement) {
0710: result = setupChildtriggerContext(e
0711: .getChildTriggerName(), e
0712: .getChildTriggerValues());
0713: }
0714: } catch (ExitTriggeredException e) {
0715: synchronized (mElement) {
0716: result = handleExitTrigger(e.getExitName());
0717: }
0718: } catch (StepBackException e) {
0719: ContinuationContext context = e.getContext();
0720:
0721: // register context
0722: ContinuationManager manager = mElementInfo.getSite()
0723: .getContinuationManager();
0724: manager.addContext(context);
0725:
0726: synchronized (mElement) {
0727: // preserve the continuation ID of this element
0728: String context_id = getContextId();
0729: ElementResultState result_state = mRequestState
0730: .getElementResultStatesObtained().get(
0731: context_id);
0732: if (null == result_state) {
0733: result_state = mElementInfo.getStateStore()
0734: .createNewResultState(context_id);
0735: mRequestState.getElementResultStatesObtained().put(
0736: result_state);
0737: }
0738: result_state.setContinuationId(context.getId());
0739:
0740: // try to obtain the id of the previous continuation
0741: String stepbackid = e.lookupStepBackId();
0742:
0743: // there is no previous continuation, so start from the beginning again
0744: if (null == stepbackid) {
0745: ContinuationContext.clearActiveContext();
0746: mRequestState.setContinuationId(null);
0747: } else {
0748: mRequestState.setContinuationId(stepbackid);
0749: }
0750:
0751: result = new ElementContext(mElement, mRequestState,
0752: mResponse);
0753: result.mSteppedBack = true;
0754: }
0755: } catch (ForwardException e) {
0756: synchronized (mElement) {
0757: handleForward(e.getUrl());
0758: }
0759: } catch (RedirectException e) {
0760: synchronized (mElement) {
0761: getResponse().sendRedirect(e.getUrl());
0762: }
0763: } finally {
0764: synchronized (mElement) {
0765: try {
0766: // flush the output buffer
0767: if (mResponse != null) {
0768: mResponse.flush();
0769: }
0770:
0771: // trace element activity
0772: mElementInfo.outputTrace(start, mRequestState);
0773: } catch (EngineException e) {
0774: // if errors occurred during flushing it means that the client has
0775: // disconnected, disregard them
0776: } finally {
0777: // clear the request if this is needed, this typically happens
0778: // for continuations, to prevent the request to be cloned when
0779: // element instances are cloned
0780: if (clear_request) {
0781: mRequestState.clearRequest();
0782: }
0783: }
0784: }
0785: }
0786:
0787: return result;
0788: }
0789:
0790: private ElementContext setupChildtriggerContext(
0791: String childtrigger, String[] values)
0792: throws EngineException {
0793: ElementContext element_context = null;
0794: Map<String, String[]> child_inputs = null;
0795:
0796: if (mElementState.inInheritanceStructure()) {
0797: // construct the child element
0798: ElementInfo child_element_info = mElementState
0799: .getInheritanceStack().pop();
0800:
0801: // verify if the trigger wasn't raised automatically, if this is the
0802: // case, the first trigger context has to be removed from the trigger
0803: // list since it has been used by this element
0804: if (mElementState.isNextChildTrigger(mElementInfo,
0805: childtrigger)) {
0806: // obtain the stored exit inputs
0807: child_inputs = mElementState.nextTrigger()
0808: .getParameters();
0809: }
0810: // since the current element deferred the logical flow to its child,
0811: // record the child trigger that caused this
0812: else {
0813: child_inputs = getChildInputValues(child_element_info);
0814:
0815: // don't store an child trigger which isn't dependent on watched values in the
0816: // trigger list, the whole element will be executed each time for those triggers
0817: if (childtrigger != null) {
0818: mElementState
0819: .addTrigger(TriggerContext
0820: .generateChildTrigger(mElementInfo,
0821: childtrigger, values,
0822: child_inputs));
0823: }
0824: }
0825:
0826: // construct the child element's context
0827: mElementState.setTriggerInputs(child_inputs);
0828: element_context = mRequestState.getElementContext(
0829: child_element_info, mResponse);
0830: }
0831:
0832: return element_context;
0833: }
0834:
0835: private ElementContext handleExitTrigger(String exit)
0836: throws EngineException {
0837: // get the the flowlink to check first if it's a redirection
0838: FlowLink flowlink = mElementInfo.getFlowLink(exit);
0839: if (null == flowlink) {
0840: throw new ExitNotAttachedException(mElementInfo
0841: .getDeclarationName(), exit);
0842: }
0843:
0844: if (flowlink.isRedirect()) {
0845: getResponse().sendRedirect(
0846: _getExitQueryUrl(flowlink, null,
0847: mOutputs.aggregateValues(), null)
0848: .toString());
0849: return null;
0850: } else {
0851: return setupExitContext(exit);
0852: }
0853: }
0854:
0855: private ElementContext setupExitContext(String exit)
0856: throws EngineException {
0857: // get the element info of the exit target
0858: FlowLink flowlink = mElementInfo.getFlowLink(exit);
0859: if (null == flowlink) {
0860: throw new ExitNotAttachedException(mElementInfo
0861: .getDeclarationName(), exit);
0862: }
0863: ElementInfo target = flowlink.getExitTarget(mRequestState);
0864:
0865: // handle embedding cancellation
0866: if (mRequestState.isEmbedded() && flowlink.cancelEmbedding()) {
0867: // this flag is set in the embedding context to indicate that the
0868: // embedding needs to be cancelled, it will be checked by the
0869: // processEmbeddedElement method of the embedding element
0870: mRequestState.getEmbeddingContext()
0871: .setCancelEmbedding(true);
0872:
0873: // clear all current output buffers
0874: RequestState request_state = mRequestState;
0875: while (request_state.isEmbedded()) {
0876: request_state.getEmbeddingContext().getElementContext()
0877: .getResponse().clearBuffer();
0878: request_state = request_state.getEmbeddingContext()
0879: .getElementContext().getRequestState();
0880: }
0881: }
0882:
0883: Map<String, String[]> exit_request_params = null;
0884: Map<String, String[]> exit_inputs = null;
0885: Stack<ElementInfo> inheritance_stack = null;
0886:
0887: Set<Map.Entry<String, String[]>> output_entries = mOutputs
0888: .aggregateValues().entrySet();
0889: if (mElementState.inInheritanceStructure()
0890: && !flowlink.cancelInheritance()) {
0891: // verify if the trigger wasn't raised automatically, if this is the
0892: // case, the first trigger context has to be removed from the trigger
0893: // list since it has been used by this element
0894: if (mElementState.isNextExitTrigger(mElementInfo, exit)) {
0895: exit_request_params = mElementState
0896: .getRequestParameters();
0897: // obtain the stored exit inputs
0898: exit_inputs = mElementState.nextTrigger()
0899: .getParameters();
0900: }
0901: // since the current element deferred the logical flow to an exit,
0902: // record this action in the trigger list
0903: else {
0904: exit_request_params = new HashMap<String, String[]>();
0905: exit_request_params.put(
0906: ReservedParameters.CHILDREQUEST,
0907: new String[] { getEncodedChildRequest() });
0908:
0909: exit_request_params
0910: .put(
0911: ReservedParameters.TRIGGERLIST,
0912: mElementState
0913: .getRequestParameterValues(ReservedParameters.TRIGGERLIST));
0914:
0915: exit_inputs = getExitInputValues(flowlink,
0916: output_entries, target, flowlink.isSnapback());
0917:
0918: mElementState.addTrigger(TriggerContext
0919: .generateExitTrigger(mElementInfo, exit,
0920: exit_inputs));
0921: }
0922:
0923: inheritance_stack = mElementState.getInheritanceStack();
0924:
0925: // check for successive inheritance stacks
0926: Stack<ElementInfo> dest_inheritance_stack = target
0927: .getInheritanceStack();
0928: if (dest_inheritance_stack != null) {
0929: inheritance_stack.addAll(dest_inheritance_stack);
0930: target = inheritance_stack.pop();
0931: }
0932: } else {
0933: exit_request_params = new HashMap<String, String[]>();
0934: exit_inputs = getExitInputValues(flowlink, output_entries,
0935: target, flowlink.isSnapback());
0936:
0937: mRequestState.setTarget(target);
0938:
0939: // obtain the inheritance stack and if it exists the top parent
0940: // this isn't done if an inheritance structure is already present
0941: Stack<ElementInfo> dest_inheritance_stack = target
0942: .getInheritanceStack();
0943: if (dest_inheritance_stack != null) {
0944: inheritance_stack = new Stack<ElementInfo>();
0945: inheritance_stack.addAll(dest_inheritance_stack);
0946: target = inheritance_stack.pop();
0947: }
0948: }
0949:
0950: // the request method isn't get or post anymore since all parameters have
0951: // been removed
0952: mElementState.setMethod(RequestMethod.EXIT);
0953:
0954: // construct the target element's context
0955: mElementState.setRequestParameters(exit_request_params);
0956: mElementState.setInheritanceStack(inheritance_stack);
0957: mElementState.setTriggerInputs(exit_inputs);
0958:
0959: // return the new element context
0960: return mRequestState.getElementContext(target, mResponse);
0961: }
0962:
0963: private void handleForward(String url) {
0964: boolean is_absolute_url = true;
0965: if (-1 == url.indexOf(":/")) {
0966: is_absolute_url = false;
0967:
0968: StringBuilder absolute_url = new StringBuilder();
0969: absolute_url.append(mRequestState
0970: .getWebappRootUrl(RifeConfig.Engine
0971: .getLocalForwardPort()));
0972: if (url.startsWith("/")) {
0973: absolute_url.append(url.substring(1));
0974: } else {
0975: absolute_url.append(url);
0976: }
0977: url = absolute_url.toString();
0978: }
0979:
0980: try {
0981: Map<String, String> request_header_map = new HashMap<String, String>();
0982:
0983: Request request = mRequestState.getRequest();
0984: Enumeration<String> request_header_names = request
0985: .getHeaderNames();
0986:
0987: // convert the headers to a map
0988: if (request_header_names.hasMoreElements()) {
0989: String header_name = null;
0990: String header_name_lowercase = null;
0991: String header_value = null;
0992: do {
0993: header_name = request_header_names.nextElement();
0994: if (null != header_name) {
0995: header_name_lowercase = header_name
0996: .toLowerCase();
0997: header_value = request.getHeader(header_name);
0998: if (is_absolute_url
0999: && ("host"
1000: .equals(header_name_lowercase)
1001: || "connection"
1002: .equals(header_name_lowercase)
1003: || "keep-alive"
1004: .equals(header_name_lowercase)
1005: || "content-type"
1006: .equals(header_name_lowercase) || "content-length"
1007: .equals(header_name_lowercase))) {
1008: continue;
1009: }
1010: request_header_map.put(header_name,
1011: header_value);
1012: }
1013: } while (request_header_names.hasMoreElements());
1014: }
1015:
1016: // retrieve the page
1017: HttpUtils.Page page = new HttpUtils.Request(url).headers(
1018: request_header_map).retrieve();
1019:
1020: // incorporate the page data in the current request
1021: if ((page.getResponseCode() / 100) != 2) {
1022: // report errors
1023: mResponse.sendError(page.getResponseCode(), page
1024: .getResponseMessage());
1025: } else {
1026: // preserve the status code
1027: mResponse.setStatus(page.getResponseCode());
1028: }
1029:
1030: if (page.getContent() != null) {
1031: mResponse.print(page.getContent());
1032: }
1033:
1034: for (Map.Entry<String, List<String>> header : page
1035: .getHeaders().entrySet()) {
1036: if (header.getKey() != null) {
1037: String key = header.getKey().toLowerCase();
1038:
1039: // strip out several duplicate headers
1040: if (key.equals("accept-encoding")
1041: || key.equals("content-encoding")
1042: || key.equals("content-length")
1043: || key.equals("date") || key.equals("host")
1044: || key.equals("server")
1045: || key.equals("transfer-encoding")) {
1046: continue;
1047: }
1048:
1049: // handle the content type differently
1050: if (key.equals("content-type")) {
1051: mResponse.setContentType(HttpUtils
1052: .extractMimeTypeFromContentType(page
1053: .getContentType()));
1054: continue;
1055: }
1056:
1057: for (String header_value : header.getValue()) {
1058: mResponse.addHeader(header.getKey(),
1059: header_value);
1060: }
1061: }
1062: }
1063: } catch (IOException e) {
1064: mResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
1065: }
1066:
1067: RequestDispatcher dispatcher = mRequestState.getRequest()
1068: .getRequestDispatcher(url);
1069: if (null == dispatcher) {
1070: mResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
1071: }
1072: }
1073:
1074: RequestState getRequestState() {
1075: return mRequestState;
1076: }
1077:
1078: ElementInfo getElementInfo() {
1079: return mElementInfo;
1080: }
1081:
1082: ElementSupport getElementSupport() {
1083: return mElement;
1084: }
1085:
1086: ElementExecutionState getElementState() {
1087: return mElementState;
1088: }
1089:
1090: Response getResponse() {
1091: return mResponse;
1092: }
1093:
1094: void setResponse(Response response) {
1095: mResponse = response;
1096: }
1097:
1098: Template getHtmlTemplate(String name, String encoding,
1099: TemplateTransformer transformer) throws TemplateException {
1100: if (null == name)
1101: throw new IllegalArgumentException("name can't be null.");
1102: if (0 == name.length())
1103: throw new IllegalArgumentException("name can't be empty.");
1104:
1105: return TemplateFactory.ENGINEHTML.get(name, encoding,
1106: transformer);
1107: }
1108:
1109: Template getXhtmlTemplate(String name, String encoding,
1110: TemplateTransformer transformer) throws TemplateException {
1111: if (null == name)
1112: throw new IllegalArgumentException("name can't be null.");
1113: if (0 == name.length())
1114: throw new IllegalArgumentException("name can't be empty.");
1115:
1116: return TemplateFactory.ENGINEXHTML.get(name, encoding,
1117: transformer);
1118: }
1119:
1120: Template getXmlTemplate(String name, String encoding,
1121: TemplateTransformer transformer) throws TemplateException {
1122: if (null == name)
1123: throw new IllegalArgumentException("name can't be null.");
1124: if (0 == name.length())
1125: throw new IllegalArgumentException("name can't be empty.");
1126:
1127: return TemplateFactory.ENGINEXML.get(name, encoding,
1128: transformer);
1129: }
1130:
1131: Template getTxtTemplate(String name, String encoding,
1132: TemplateTransformer transformer) throws TemplateException {
1133: if (null == name)
1134: throw new IllegalArgumentException("name can't be null.");
1135: if (0 == name.length())
1136: throw new IllegalArgumentException("name can't be empty.");
1137:
1138: return TemplateFactory.ENGINETXT.get(name, encoding,
1139: transformer);
1140: }
1141:
1142: void processEmbeddedElementsEarly(Template template,
1143: ElementSupport embeddingElement) {
1144: // process the embedded elements
1145: if (template.hasFilteredValues(TAG_ELEMENT)) {
1146: List<String[]> element_tags = template
1147: .getFilteredValues(TAG_ELEMENT);
1148: for (String[] captured_groups : element_tags) {
1149: // only embed the element if the value hasn't been set in the
1150: // template yet and is declared as 'early'
1151: if (!template.isValueSet(captured_groups[0])
1152: && captured_groups[2].equals("-")) {
1153: processEmbeddedElement(captured_groups[0],
1154: template, embeddingElement,
1155: captured_groups[3], captured_groups[4],
1156: null);
1157: }
1158: }
1159:
1160: for (String[] captured_groups : element_tags) {
1161: // only embed the element if the value hasn't been set in the
1162: // template yet and has no specific priority
1163: if (!template.isValueSet(captured_groups[0])
1164: && 0 == captured_groups[2].length()) {
1165: processEmbeddedElement(captured_groups[0],
1166: template, embeddingElement,
1167: captured_groups[3], captured_groups[4],
1168: null);
1169: }
1170: }
1171: }
1172: }
1173:
1174: void processEmbeddedElementsLate(Template template,
1175: ElementSupport embeddingElement) {
1176: // process the embedded elements
1177: if (template.hasFilteredValues(TAG_ELEMENT)) {
1178: List<String[]> element_tags = template
1179: .getFilteredValues(TAG_ELEMENT);
1180: for (String[] captured_groups : element_tags) {
1181: // only embed the element if the value hasn't been set in the
1182: // template yet and is declared as late
1183: if (!template.isValueSet(captured_groups[0])
1184: && captured_groups[2].equals("+")) {
1185: processEmbeddedElement(captured_groups[0],
1186: template, embeddingElement,
1187: captured_groups[3], captured_groups[4],
1188: null);
1189: }
1190: }
1191: }
1192: }
1193:
1194: void print(Template template) throws TemplateException,
1195: EngineException {
1196: List<String> set_values = processTemplate(template);
1197:
1198: // set the content type
1199: if (!mResponse.isContentTypeSet()) {
1200: String content_type = template.getDefaultContentType();
1201: if (null == content_type) {
1202: content_type = RifeConfig.Engine
1203: .getDefaultContentType();
1204: }
1205:
1206: mResponse.setContentType(content_type);
1207: }
1208:
1209: // print the element contents with the auto-generated values
1210: mResponse.print(template);
1211:
1212: // clean up the values that were set
1213: template.removeValues(set_values);
1214: }
1215:
1216: List<String> processTemplate(Template template)
1217: throws TemplateException, EngineException {
1218: List<String> set_values = new ArrayList<String>();
1219:
1220: // pre-obtain the output entries, since they process the outjection logic
1221: Map<String, String[]> output_value_map = mOutputs
1222: .aggregateValues();
1223: Set<Map.Entry<String, String[]>> output_value_entries = output_value_map
1224: .entrySet();
1225:
1226: // retrieve the template encoder
1227: TemplateEncoder encoder = template.getEncoder();
1228:
1229: // process the filtered roleuser tags
1230: evaluateExpressionRoleUserTags(set_values, template, null);
1231:
1232: // create values for the exit urls
1233: Set<Map.Entry<String, FlowLink>> exit_entries = mElementInfo
1234: .getExitEntries();
1235: if (exit_entries.size() > 0) {
1236: String exit_name = null;
1237: FlowLink exit_flowlink = null;
1238: String exit_query_value_id = null;
1239: String exit_form_value_id = null;
1240: String exit_params_value_id = null;
1241: String exit_paramsjs_value_id = null;
1242:
1243: for (Map.Entry<String, FlowLink> exit_entry : exit_entries) {
1244: if (exit_entry.getValue() != null) {
1245: exit_name = exit_entry.getKey();
1246: exit_flowlink = exit_entry.getValue();
1247:
1248: exit_query_value_id = PREFIX_EXIT_QUERY + exit_name;
1249: exit_form_value_id = PREFIX_EXIT_FORM + exit_name;
1250: exit_params_value_id = PREFIX_EXIT_PARAMS
1251: + exit_name;
1252: exit_paramsjs_value_id = PREFIX_EXIT_PARAMS
1253: + exit_name;
1254:
1255: if (template.hasValueId(exit_query_value_id)
1256: && !template
1257: .isValueSet(exit_query_value_id)) {
1258: template.setValue(exit_query_value_id,
1259: _getExitQueryUrl(exit_flowlink, null,
1260: output_value_map, null)
1261: .encoder(encoder));
1262: set_values.add(exit_query_value_id);
1263: }
1264:
1265: if (template.hasValueId(exit_form_value_id)) {
1266: // only substitute the template value if it hasn't been specified yet
1267: // this allows for user overriding
1268: if (!template.isValueSet(exit_form_value_id)) {
1269: template.setValue(exit_form_value_id,
1270: _getExitFormUrl(exit_flowlink,
1271: null, output_value_map)
1272: .encoder(encoder));
1273: set_values.add(exit_form_value_id);
1274: }
1275:
1276: // only substitute the form parameters template value if the url is present
1277: if (template.hasValueId(exit_params_value_id)) {
1278: // only substitute the template value if it hasn't been specified yet
1279: // this allows for user overriding
1280: if (!template
1281: .isValueSet(exit_params_value_id)) {
1282: template
1283: .setValue(
1284: exit_params_value_id,
1285: _getExitFormParameters(
1286: exit_flowlink,
1287: output_value_map,
1288: null));
1289: set_values.add(exit_params_value_id);
1290: }
1291: } else if (template
1292: .hasValueId(exit_paramsjs_value_id)) {
1293: // only substitute the template value if it hasn't been specified yet
1294: // this allows for user overriding
1295: if (!template
1296: .isValueSet(exit_paramsjs_value_id)) {
1297: template
1298: .setValue(
1299: exit_paramsjs_value_id,
1300: _getExitFormParametersJavascript(
1301: exit_flowlink,
1302: output_value_map,
1303: null));
1304: set_values.add(exit_paramsjs_value_id);
1305: }
1306: } else {
1307: throw new EngineException(
1308: "The required template value '"
1309: + exit_params_value_id
1310: + "' is not present. Replacement of the template value '"
1311: + exit_form_value_id
1312: + "' alone is not sufficient.");
1313: }
1314: } else {
1315: if (template.hasValueId(exit_params_value_id)) {
1316: throw new EngineException(
1317: "The template value '"
1318: + exit_params_value_id
1319: + "' was specified, while the template value '"
1320: + exit_form_value_id
1321: + "' could not be found. This is not sufficient, both are needed.");
1322: } else if (template
1323: .hasValueId(exit_paramsjs_value_id)) {
1324: throw new EngineException(
1325: "The template value '"
1326: + exit_paramsjs_value_id
1327: + "' was specified, while the template value '"
1328: + exit_form_value_id
1329: + "' could not be found. This is not sufficient, both are needed.");
1330: }
1331: }
1332: }
1333: }
1334: }
1335:
1336: // create values for submission urls
1337: String submission_query_value_id = null;
1338: String submission_form_value_id = null;
1339: String submission_params_value_id = null;
1340: String submission_paramsjs_value_id = null;
1341:
1342: for (String submission_name : mElementInfo.getSubmissionNames()) {
1343: submission_query_value_id = PREFIX_SUBMISSION_QUERY
1344: + submission_name;
1345: submission_form_value_id = PREFIX_SUBMISSION_FORM
1346: + submission_name;
1347: submission_params_value_id = PREFIX_SUBMISSION_PARAMS
1348: + submission_name;
1349: submission_paramsjs_value_id = PREFIX_SUBMISSION_PARAMSJS
1350: + submission_name;
1351:
1352: if (template.hasValueId(submission_query_value_id)
1353: && !template.isValueSet(submission_query_value_id)) {
1354: template.setValue(submission_query_value_id,
1355: _getSubmissionQueryUrl(submission_name, null,
1356: null, output_value_entries).encoder(
1357: encoder));
1358: set_values.add(submission_query_value_id);
1359: }
1360:
1361: if (template.hasValueId(submission_form_value_id)) {
1362: // only substitute the template value if it hasn't been specified yet
1363: // this allows for user overriding
1364: if (!template.isValueSet(submission_form_value_id)) {
1365: template
1366: .setValue(submission_form_value_id,
1367: getSubmissionFormUrl(null).encoder(
1368: encoder));
1369: set_values.add(submission_form_value_id);
1370: }
1371:
1372: // only substitute the form parameters template value if the url is present
1373: if (template.hasValueId(submission_params_value_id)) {
1374: // only substitute the template value if it hasn't been specified yet
1375: // this allows for user overriding
1376: if (!template
1377: .isValueSet(submission_params_value_id)) {
1378: template.setValue(submission_params_value_id,
1379: _getSubmissionFormParameters(
1380: submission_name, null,
1381: output_value_entries));
1382: set_values.add(submission_params_value_id);
1383: }
1384: } else if (template
1385: .hasValueId(submission_paramsjs_value_id)) {
1386: // only substitute the template value if it hasn't been specified yet
1387: // this allows for user overriding
1388: if (!template
1389: .isValueSet(submission_paramsjs_value_id)) {
1390: template.setValue(submission_paramsjs_value_id,
1391: _getSubmissionFormParametersJavascript(
1392: submission_name, null,
1393: output_value_entries));
1394: set_values.add(submission_paramsjs_value_id);
1395: }
1396: } else {
1397: throw new EngineException(
1398: "The template value '"
1399: + submission_params_value_id
1400: + "' nor '"
1401: + submission_paramsjs_value_id
1402: + "'are not present. Replacement of the template value '"
1403: + submission_form_value_id
1404: + "' alone is not sufficient.");
1405: }
1406: } else {
1407: if (template.hasValueId(submission_params_value_id)) {
1408: throw new EngineException(
1409: "The template value '"
1410: + submission_params_value_id
1411: + "' was specified, while the template value '"
1412: + submission_form_value_id
1413: + "' could not be found. This is not sufficient, both are needed.");
1414: } else if (template
1415: .hasValueId(submission_paramsjs_value_id)) {
1416: throw new EngineException(
1417: "The template value '"
1418: + submission_paramsjs_value_id
1419: + "' was specified, while the template value '"
1420: + submission_form_value_id
1421: + "' could not be found. This is not sufficient, both are needed.");
1422: }
1423: }
1424: }
1425:
1426: // create values for properties
1427: if (template.hasFilteredValues(TAG_PROPERTY)) {
1428: String property_value_id = null;
1429: String property_value = null;
1430:
1431: for (String[] property_tag : template
1432: .getFilteredValues(TAG_PROPERTY)) {
1433: property_value_id = PREFIX_PROPERTY + property_tag[1];
1434: if (template.hasValueId(property_value_id)
1435: && !template.isValueSet(property_value_id)) {
1436: property_value = mElementInfo
1437: .getPropertyString(property_tag[1]);
1438: if (property_value != null) {
1439: template.setValue(property_value_id, encoder
1440: .encode(property_value));
1441: set_values.add(property_value_id);
1442: }
1443: }
1444: }
1445: }
1446:
1447: // create values for inputs
1448: String input_value_id = null;
1449: String[] input_values = null;
1450:
1451: for (Map.Entry<String, String[]> input_entry : mElementState
1452: .getInputEntries()) {
1453: if (mElementInfo.containsInput(input_entry.getKey())
1454: && mElementState
1455: .hasInputValue(input_entry.getKey())) {
1456: input_value_id = PREFIX_INPUT + input_entry.getKey();
1457: input_values = input_entry.getValue();
1458: if (template.hasValueId(input_value_id)
1459: && !template.isValueSet(input_value_id)) {
1460: template.setValue(input_value_id, encoder
1461: .encode(input_values[0]));
1462: set_values.add(input_value_id);
1463: }
1464:
1465: set_values.addAll(selectInputParameter(template,
1466: input_entry.getKey(), input_values));
1467: }
1468: }
1469:
1470: // create values for outputs
1471: String output_value_id = null;
1472:
1473: for (Map.Entry<String, String[]> output_entry : output_value_entries) {
1474: output_value_id = PREFIX_OUTPUT + output_entry.getKey();
1475: if (template.hasValueId(output_value_id)
1476: && !template.isValueSet(output_value_id)
1477: && output_entry.getValue() != null) {
1478: template.setValue(output_value_id, encoder
1479: .encode(output_entry.getValue()[0]));
1480: set_values.add(output_value_id);
1481: }
1482: }
1483:
1484: // create values for global variables
1485: for (String globalvar_name : mElementInfo.getGlobalVarNames()) {
1486: if (mElementState.hasInputValue(globalvar_name)) {
1487: input_value_id = PREFIX_INPUT + globalvar_name;
1488: if (template.hasValueId(input_value_id)
1489: && !template.isValueSet(input_value_id)) {
1490: template.setValue(input_value_id, encoder
1491: .encode(mElementState
1492: .getInput(globalvar_name)));
1493: set_values.add(input_value_id);
1494: }
1495:
1496: set_values.addAll(selectInputParameter(template,
1497: globalvar_name, mElementState
1498: .getInputValues(globalvar_name)));
1499: }
1500:
1501: String[] global_output_value = output_value_map
1502: .get(globalvar_name);
1503: if (global_output_value != null) {
1504: output_value_id = PREFIX_OUTPUT + globalvar_name;
1505: if (template.hasValueId(output_value_id)
1506: && !template.isValueSet(output_value_id)) {
1507: template.setValue(output_value_id, encoder
1508: .encode(global_output_value[0]));
1509: set_values.add(output_value_id);
1510: }
1511: }
1512: }
1513:
1514: // create values for in cookies
1515: String incookie_value_id = null;
1516: for (Map.Entry<String, String> incookie_entry : getIncookieEntries()) {
1517: if (mElementInfo.containsIncookie(incookie_entry.getKey())
1518: || mElementInfo.containsGlobalCookie(incookie_entry
1519: .getKey())) {
1520: incookie_value_id = PREFIX_INCOOKIE
1521: + incookie_entry.getKey();
1522: if (template.hasValueId(incookie_value_id)
1523: && !template.isValueSet(incookie_value_id)) {
1524: template.setValue(incookie_value_id, encoder
1525: .encode(incookie_entry.getValue()));
1526: set_values.add(incookie_value_id);
1527: }
1528: }
1529: }
1530:
1531: // create values for out cookies
1532: String outcookie_value_id = null;
1533: for (Map.Entry<String, String> outcookie_entry : mOutcookies
1534: .aggregateValues().entrySet()) {
1535: if (mElementInfo
1536: .containsOutcookiePossibility(outcookie_entry
1537: .getKey())) {
1538: outcookie_value_id = PREFIX_OUTCOOKIE
1539: + outcookie_entry.getKey();
1540: if (template.hasValueId(outcookie_value_id)
1541: && !template.isValueSet(outcookie_value_id)) {
1542: template.setValue(outcookie_value_id, encoder
1543: .encode(outcookie_entry.getValue()));
1544: set_values.add(outcookie_value_id);
1545: }
1546: }
1547: }
1548:
1549: // set the webapp root
1550: if (template.hasValueId(ID_WEBAPP_ROOTURL)
1551: && !template.isValueSet(ID_WEBAPP_ROOTURL)) {
1552: template.setValue(ID_WEBAPP_ROOTURL, mRequestState
1553: .getWebappRootUrl(-1));
1554: set_values.add(ID_WEBAPP_ROOTURL);
1555: }
1556:
1557: // set the server root
1558: if (template.hasValueId(ID_SERVER_ROOTURL)
1559: && !template.isValueSet(ID_SERVER_ROOTURL)) {
1560: template.setValue(ID_SERVER_ROOTURL, mRequestState
1561: .getServerRootUrl(-1));
1562: set_values.add(ID_SERVER_ROOTURL);
1563: }
1564:
1565: // create values for submission parameters and beans
1566: String[] submission_param_values = null;
1567: String submission_param_value_id = null;
1568:
1569: for (Submission submission : mElementInfo.getSubmissions()) {
1570: // create the parameters
1571: for (String submission_param_name : submission
1572: .getParameterNames()) {
1573: if (mElementState
1574: .hasRequestParameterValue(submission_param_name)) {
1575: submission_param_values = mElementState
1576: .getRequestParameterValues(submission_param_name);
1577:
1578: submission_param_value_id = PREFIX_PARAM
1579: + submission_param_name;
1580: if (template.hasValueId(submission_param_value_id)
1581: && !template
1582: .isValueSet(submission_param_value_id)) {
1583: template
1584: .setValue(
1585: submission_param_value_id,
1586: encoder
1587: .encode(submission_param_values[0]));
1588: set_values.add(submission_param_value_id);
1589: }
1590:
1591: set_values.addAll(selectSubmissionParameter(
1592: template, submission_param_name,
1593: submission_param_values));
1594: }
1595: }
1596:
1597: // create the bean forms
1598: BeanHandler bean_handler = template.getBeanHandler();
1599: if (bean_handler != null) {
1600: FormBuilder form_builder = bean_handler
1601: .getFormBuilder();
1602: if (form_builder != null) {
1603: for (BeanDeclaration bean : submission.getBeans()) {
1604: try {
1605: Map<String, String[]> parameters = null;
1606: if (hasSubmission()
1607: && submission.getName().equals(
1608: getSubmission())) {
1609: parameters = mElementState
1610: .getRequestParameters();
1611: }
1612: form_builder.generateForm(template, bean
1613: .getBeanClass(), parameters, bean
1614: .getPrefix());
1615: } catch (Throwable e) {
1616: throw new SubmissionBeanFormGenerationErrorException(
1617: mElementInfo.getDeclarationName(),
1618: submission.getName(), bean
1619: .getClassname(), e);
1620: }
1621: }
1622: }
1623: }
1624: }
1625:
1626: // process the late embedded elements
1627: processEmbeddedElementsLate(template, mElement);
1628:
1629: return set_values;
1630: }
1631:
1632: void triggerChild(String childTriggerName,
1633: String[] childTriggerValues) throws EngineException {
1634: mElement.enableRequestAccess(false);
1635: try {
1636: if (mElement.childTriggered(childTriggerName,
1637: childTriggerValues)) {
1638: throw new ChildTriggeredException(childTriggerName,
1639: childTriggerValues);
1640: }
1641: } finally {
1642: mElement.enableRequestAccess(true);
1643: }
1644: }
1645:
1646: boolean hasSubmission() {
1647: return null != getSubmission();
1648: }
1649:
1650: boolean hasSubmission(String name) {
1651: String submission = getSubmission();
1652: return submission != null && submission.equals(name);
1653:
1654: }
1655:
1656: String getSubmission() {
1657: if (null == mSubmission) {
1658: return null;
1659: }
1660:
1661: return mSubmission;
1662: }
1663:
1664: private void validateParameter(String parameterName)
1665: throws EngineException {
1666: assert parameterName != null;
1667: assert parameterName.length() > 0;
1668:
1669: boolean found = false;
1670: for (Submission submission : mElementInfo.getSubmissions()) {
1671: if (submission.containsParameter(parameterName)) {
1672: found = true;
1673: break;
1674: }
1675: }
1676:
1677: if (!found) {
1678: throw new ParameterUnknownException(mElementInfo
1679: .getDeclarationName(), parameterName);
1680: }
1681: }
1682:
1683: private void validateFile(String fileName) throws EngineException {
1684: assert fileName != null;
1685: assert fileName.length() > 0;
1686:
1687: boolean found = false;
1688: for (Submission submission : mElementInfo.getSubmissions()) {
1689: if (submission.containsFile(fileName)) {
1690: found = true;
1691: break;
1692: }
1693: }
1694:
1695: if (!found) {
1696: throw new FileUnknownException(mElementInfo
1697: .getDeclarationName(), fileName);
1698: }
1699: }
1700:
1701: boolean isInputEmpty(String name) throws EngineException {
1702: String input = getInput(name);
1703:
1704: return null == input || input.trim().equals("");
1705: }
1706:
1707: String getInput(String name) throws EngineException {
1708: assert name != null;
1709: assert name.length() > 0;
1710:
1711: mElementInfo.validateInputName(name);
1712:
1713: String input = mElementState.getInput(name);
1714:
1715: if (null == input && mElementInfo.hasInputDefaults()) {
1716: String[] default_values = mElementInfo
1717: .getInputDefaultValues(name);
1718: if (default_values != null) {
1719: input = default_values[0];
1720: }
1721: }
1722:
1723: if (null == input && mElementInfo.hasGlobalVarDefaults()) {
1724: String[] default_values = mElementInfo
1725: .getGlobalVarDefaultValues(name);
1726: if (default_values != null) {
1727: input = default_values[0];
1728: }
1729: }
1730:
1731: return input;
1732: }
1733:
1734: String[] getInputValues(String name) throws EngineException {
1735: assert name != null;
1736: assert name.length() > 0;
1737:
1738: mElementInfo.validateInputName(name);
1739:
1740: String[] input_values = mElementState.getInputValues(name);
1741:
1742: if (null == input_values && mElementInfo.hasInputDefaults()) {
1743: input_values = mElementInfo.getInputDefaultValues(name);
1744: }
1745:
1746: if (null == input_values && mElementInfo.hasGlobalVarDefaults()) {
1747: input_values = mElementInfo.getGlobalVarDefaultValues(name);
1748: }
1749:
1750: return input_values;
1751: }
1752:
1753: boolean hasInputValue(String name) throws EngineException {
1754: assert name != null;
1755: assert name.length() > 0;
1756:
1757: mElementInfo.validateInputName(name);
1758:
1759: return mElementState.hasInputValue(name)
1760: || mElementInfo.hasInputDefaultValues(name)
1761: || mElementInfo.hasGlobalVarDefaultValues(name);
1762: }
1763:
1764: Collection<String> selectInputParameter(Template template,
1765: String name, String[] values) {
1766: return selectParameter(template, PREFIX_INPUT + name, values);
1767: }
1768:
1769: OutputValues getOutputs() {
1770: return mOutputs;
1771: }
1772:
1773: void setOutput(String name, String value) throws EngineException {
1774: assert name != null;
1775: assert name.length() > 0;
1776: assert value != null;
1777:
1778: mElementInfo.validateOutputName(name);
1779:
1780: // create a string array
1781: String[] value_array = new String[] { value };
1782:
1783: // store the value
1784: setOutputValues(name, value_array);
1785:
1786: if (mElementState.inInheritanceStructure()
1787: && mElementInfo.containsChildTrigger(name)) {
1788: triggerChild(name, value_array);
1789: }
1790: }
1791:
1792: void setOutput(String name, String[] values) throws EngineException {
1793: assert name != null;
1794: assert name.length() > 0;
1795: assert values != null;
1796: assert values.length > 0;
1797:
1798: mElementInfo.validateOutputName(name);
1799:
1800: setOutputValues(name, values);
1801:
1802: if (mElementState.inInheritanceStructure()
1803: && mElementInfo.containsChildTrigger(name)) {
1804: triggerChild(name, values);
1805: }
1806: }
1807:
1808: void setOutput(String name, Object value,
1809: ConstrainedProperty constrainedProperty)
1810: throws EngineException {
1811: assert name != null;
1812: assert name.length() > 0;
1813: assert value != null;
1814:
1815: String[] value_array = getOutputObjectValues(name, value,
1816: constrainedProperty);
1817:
1818: // store the value
1819: setOutputValues(name, value_array);
1820:
1821: if (mElementState.inInheritanceStructure()
1822: && mElementInfo.containsChildTrigger(name)) {
1823: triggerChild(name, value_array);
1824: }
1825: }
1826:
1827: private String[] getOutputObjectValues(String name, Object value,
1828: ConstrainedProperty constrainedProperty)
1829: throws EngineException {
1830: mElementInfo.validateOutputName(name);
1831:
1832: // create a string array
1833: String[] value_array = null;
1834:
1835: // convert the value to a string representation
1836: Class value_type = value.getClass();
1837: if (value_type.isArray() || !(value instanceof Serializable)
1838: || ClassUtils.isBasic(value_type)) {
1839: value_array = ArrayUtils.createStringArray(value,
1840: constrainedProperty);
1841: } else {
1842: try {
1843: value_array = new String[] { SerializationUtils
1844: .serializeToString((Serializable) value) };
1845: } catch (SerializationUtilsErrorException e) {
1846: throw new UnserializableOutputValueException(
1847: mElementInfo.getDeclarationName(), name, value,
1848: e);
1849: }
1850: }
1851:
1852: return value_array;
1853: }
1854:
1855: void addOutputValue(String name, String value)
1856: throws EngineException {
1857: assert name != null;
1858: assert name.length() > 0;
1859: assert value != null;
1860:
1861: mElementInfo.validateOutputName(name);
1862:
1863: String[] value_array = null;
1864:
1865: String[] existing_values = mOutputs.get(name);
1866: if (existing_values != null) {
1867: value_array = ArrayUtils.join(existing_values, value);
1868: } else {
1869: value_array = new String[] { value };
1870: }
1871:
1872: setOutputValues(name, value_array);
1873:
1874: if (mElementState.inInheritanceStructure()
1875: && mElementInfo.containsChildTrigger(name)) {
1876: triggerChild(name, value_array);
1877: }
1878: }
1879:
1880: void addOutputValues(String name, String[] values)
1881: throws EngineException {
1882: assert name != null;
1883: assert name.length() > 0;
1884: assert values != null;
1885: assert values.length > 0;
1886:
1887: mElementInfo.validateOutputName(name);
1888:
1889: String[] value_array = null;
1890:
1891: String[] existing_values = mOutputs.get(name);
1892: if (existing_values != null) {
1893: value_array = ArrayUtils.join(existing_values, values);
1894: } else {
1895: value_array = values;
1896: }
1897:
1898: setOutputValues(name, value_array);
1899:
1900: if (mElementState.inInheritanceStructure()
1901: && mElementInfo.containsChildTrigger(name)) {
1902: triggerChild(name, value_array);
1903: }
1904: }
1905:
1906: void addOutputValue(String name, Object value)
1907: throws EngineException {
1908: assert name != null;
1909: assert name.length() > 0;
1910: assert value != null;
1911:
1912: mElementInfo.validateOutputName(name);
1913:
1914: // convert the value to a string representation
1915: String value_text = null;
1916: Class value_type = value.getClass();
1917: if (!(value instanceof Serializable)
1918: || ClassUtils.isBasic(value_type)) {
1919: value_text = String.valueOf(value);
1920: } else if (value instanceof Serializable) {
1921: try {
1922: value_text = SerializationUtils
1923: .serializeToString((Serializable) value);
1924: } catch (SerializationUtilsErrorException e) {
1925: throw new UnserializableOutputValueException(
1926: mElementInfo.getDeclarationName(), name, value,
1927: e);
1928: }
1929: } else {
1930: value_text = String.valueOf(value);
1931: }
1932:
1933: addOutputValue(name, value_text);
1934: }
1935:
1936: void clearOutput(String name) throws EngineException {
1937: assert name != null;
1938: assert name.length() > 0;
1939:
1940: mElementInfo.validateOutputName(name);
1941:
1942: clearOutputValue(name);
1943: }
1944:
1945: void clearNamedOutputBean(String name) throws EngineException {
1946: assert name != null;
1947:
1948: mElementInfo.validateOutbeanName(name);
1949:
1950: BeanDeclaration output_bean = mElementInfo
1951: .getNamedOutbeanInfo(name);
1952: if (null == output_bean) {
1953: output_bean = mElementInfo.getNamedGlobalBeanInfo(name);
1954: }
1955:
1956: Class output_bean_class = null;
1957: try {
1958: output_bean_class = Class.forName(output_bean
1959: .getClassname());
1960: } catch (ClassNotFoundException e) {
1961: throw new NamedOutbeanClassnameErrorException(mElementInfo
1962: .getDeclarationName(), name, output_bean
1963: .getClassname());
1964: }
1965:
1966: clearOutputBean(output_bean_class, output_bean.getPrefix());
1967: }
1968:
1969: void clearOutputBean(Class beanClass, String prefix)
1970: throws EngineException {
1971: if (null == beanClass)
1972: throw new IllegalArgumentException(
1973: "beanClass can't be null.");
1974:
1975: try {
1976: // handle outputs
1977: Collection<String> output_names = mElementInfo
1978: .getOutputNames();
1979: String[] output_names_array = new String[output_names
1980: .size()];
1981: output_names.toArray(output_names_array);
1982:
1983: // handle globals
1984: Collection<String> globalvar_names = mElementInfo
1985: .getGlobalVarNames();
1986: String[] globalvar_names_array = new String[globalvar_names
1987: .size()];
1988: globalvar_names.toArray(globalvar_names_array);
1989:
1990: // merge the both arrays
1991: String[] merged_names_array = ArrayUtils.join(
1992: output_names_array, globalvar_names_array);
1993:
1994: // process all the possible output names
1995: Set<String> property_names = BeanUtils.getPropertyNames(
1996: beanClass, merged_names_array, null, prefix);
1997: for (String property_name : property_names) {
1998: clearOutput(property_name);
1999: }
2000: } catch (BeanUtilsException e) {
2001: throw new BeanClassNamesErrorException(beanClass, e);
2002: }
2003: }
2004:
2005: String[] getOutput(String name) throws EngineException {
2006: mElementInfo.validateOutputName(name);
2007:
2008: return mOutputs.aggregateValues().get(name);
2009: }
2010:
2011: private Set<Map.Entry<String, String>> getIncookieEntries() {
2012: return getCookieValues().entrySet();
2013: }
2014:
2015: boolean hasCookie(String name) throws EngineException {
2016: assert name != null;
2017: assert name.length() > 0;
2018:
2019: mElementInfo.validateIncookieName(name);
2020:
2021: return mRequestState.hasCookie(name)
2022: || mElementInfo.hasIncookieDefaultValue(name)
2023: || mElementInfo.hasGlobalCookieDefaultValue(name);
2024: }
2025:
2026: Cookie getCookie(String name) throws EngineException {
2027: assert name != null;
2028: assert name.length() > 0;
2029:
2030: mElementInfo.validateIncookieName(name);
2031:
2032: Cookie cookie = mRequestState.getCookie(name);
2033: if (null == cookie) {
2034: if (mElementInfo.hasIncookieDefaultValue(name)) {
2035: cookie = new Cookie(name, mElementInfo
2036: .getIncookieDefaultValue(name));
2037: }
2038:
2039: if (mElementInfo.hasGlobalCookieDefaultValue(name)) {
2040: cookie = new Cookie(name, mElementInfo
2041: .getGlobalCookieDefaultValue(name));
2042: }
2043: }
2044:
2045: return cookie;
2046: }
2047:
2048: String getCookieValue(String name) throws EngineException {
2049: Cookie cookie = getCookie(name);
2050: String value = null;
2051: if (cookie != null) {
2052: value = cookie.getValue();
2053: }
2054:
2055: return value;
2056: }
2057:
2058: void setCookie(Cookie cookie) throws EngineException {
2059: assert cookie != null;
2060: assert cookie.getName() != null;
2061:
2062: mElementInfo.validateOutcookieName(cookie.getName());
2063:
2064: mOutcookies.put(cookie.getName(), cookie.getValue());
2065: setCookieRaw(cookie);
2066:
2067: if (mElementState.inInheritanceStructure()
2068: && mElementInfo.containsChildTrigger(cookie.getName())) {
2069: triggerChild(cookie.getName(), new String[] { cookie
2070: .getValue() });
2071: }
2072: }
2073:
2074: void setCookieRaw(Cookie cookie) {
2075: mResponse.addCookie(cookie);
2076: mRequestState.setStateCookie(cookie);
2077: fireOutcookieSet(cookie);
2078: }
2079:
2080: HashMap<String, String> getCookieValues() throws EngineException {
2081: HashMap<String, String> result = new HashMap<String, String>();
2082:
2083: for (Map.Entry<String, String> entry : mElementInfo
2084: .getDefaultIncookies().entrySet()) {
2085: result.put(entry.getKey(), entry.getValue());
2086: }
2087:
2088: for (Map.Entry<String, String> entry : mElementInfo
2089: .getDefaultGlobalCookies().entrySet()) {
2090: result.put(entry.getKey(), entry.getValue());
2091: }
2092:
2093: for (Map.Entry<String, Cookie> entry : mRequestState
2094: .getCookies().entrySet()) {
2095: result.put(entry.getKey(), entry.getValue().getValue());
2096: }
2097:
2098: return result;
2099: }
2100:
2101: boolean hasParameterValue(String name) throws EngineException {
2102: assert name != null;
2103: assert name.length() > 0;
2104:
2105: validateParameter(name);
2106:
2107: String submission = getSubmission();
2108: if (null == submission) {
2109: return false;
2110: }
2111:
2112: return mElementState.hasRequestParameterValue(name)
2113: || mElementInfo.hasParameterDefaultValues(submission,
2114: name);
2115: }
2116:
2117: boolean isParameterEmpty(String name) throws EngineException {
2118: assert name != null;
2119: assert name.length() > 0;
2120:
2121: String parameter = getParameter(name);
2122: if (null == parameter || parameter.trim().equals("")) {
2123: return true;
2124: }
2125: return false;
2126: }
2127:
2128: String getParameter(String name) throws EngineException {
2129: assert name != null;
2130: assert name.length() > 0;
2131:
2132: validateParameter(name);
2133:
2134: String submission = getSubmission();
2135: if (null == submission) {
2136: return null;
2137: }
2138:
2139: String parameter = mElementState.getRequestParameter(name);
2140:
2141: if (null == parameter
2142: && mElementInfo.hasParameterDefaults(submission)) {
2143: String[] default_values = mElementInfo
2144: .getParameterDefaultValues(submission, name);
2145: if (default_values != null) {
2146: return default_values[0];
2147: }
2148: }
2149:
2150: return parameter;
2151: }
2152:
2153: ArrayList<String> getParameterNames(String regexp)
2154: throws EngineException {
2155: Pattern pattern = null;
2156: if (regexp != null) {
2157: pattern = Pattern.compile("^" + regexp + "$");
2158: }
2159:
2160: ArrayList<String> result = new ArrayList<String>();
2161: String submission_name = getSubmission();
2162: if (null == submission_name) {
2163: return result;
2164: }
2165:
2166: Submission submission = mElementInfo
2167: .getSubmission(submission_name);
2168: if (null == submission) {
2169: return result;
2170: }
2171:
2172: Collection<String> parameter_names = null;
2173:
2174: // add all default parameters that match
2175: parameter_names = submission.getParameterDefaultNames();
2176: for (String parameter_name : parameter_names) {
2177: if (null == pattern
2178: || pattern.matcher(parameter_name).matches()) {
2179: result.add(parameter_name);
2180: }
2181: }
2182:
2183: // go over the possible parameters and check if they have values in the request
2184: parameter_names = submission.getParameterNames();
2185: for (String parameter_name : parameter_names) {
2186: if (mElementState.hasRequestParameterValue(parameter_name)
2187: && !result.contains(parameter_name)
2188: && (null == pattern || pattern.matcher(
2189: parameter_name).matches())) {
2190: result.add(parameter_name);
2191: }
2192: }
2193:
2194: // go over all the parameter regexps and find those that match with the parameters in the request
2195: Matcher matcher = null;
2196: for (Pattern parameter_regexp : submission
2197: .getParameterRegexps()) {
2198: for (String parameter_name : mElementState
2199: .getRequestParameterNames()) {
2200: matcher = parameter_regexp.matcher(parameter_name);
2201: if (matcher.matches()) {
2202: if (mElementState
2203: .hasRequestParameterValue(parameter_name)
2204: && !result.contains(parameter_name)
2205: && (null == pattern || pattern.matcher(
2206: parameter_name).matches())) {
2207: result.add(parameter_name);
2208: }
2209: }
2210: }
2211:
2212: }
2213:
2214: return result;
2215: }
2216:
2217: String[] getParameterValues(String name) throws EngineException {
2218: assert name != null;
2219: assert name.length() > 0;
2220:
2221: validateParameter(name);
2222:
2223: String submission = getSubmission();
2224: if (null == submission) {
2225: return null;
2226: }
2227:
2228: String[] parameter_values = mElementState
2229: .getRequestParameterValues(name);
2230: if (null == parameter_values
2231: && mElementInfo.hasParameterDefaults(submission)) {
2232: return mElementInfo.getParameterDefaultValues(submission,
2233: name);
2234: }
2235:
2236: return parameter_values;
2237: }
2238:
2239: ArrayList<String> getUploadedFileNames(String regexp)
2240: throws EngineException {
2241: Pattern pattern = null;
2242: if (regexp != null) {
2243: pattern = Pattern.compile("^" + regexp + "$");
2244: }
2245:
2246: ArrayList<String> result = new ArrayList<String>();
2247: String submission_name = getSubmission();
2248: if (null == submission_name) {
2249: return result;
2250: }
2251:
2252: Submission submission = mElementInfo
2253: .getSubmission(submission_name);
2254: if (null == submission) {
2255: return result;
2256: }
2257:
2258: Collection<String> file_names = null;
2259:
2260: // go over the possible files and check if they have values in the request
2261: file_names = submission.getFileNames();
2262: for (String file_name : file_names) {
2263: if (mRequestState.hasUploadedFile(file_name)
2264: && !result.contains(file_name)
2265: && (null == pattern || pattern.matcher(file_name)
2266: .matches())) {
2267: result.add(file_name);
2268: }
2269: }
2270:
2271: // go over all the file regexps and find those that match with the files in the request
2272: Matcher matcher = null;
2273: for (Pattern file_regexp : submission.getFileRegexps()) {
2274: for (String file_name : mRequestState
2275: .getUploadedFileNames()) {
2276: matcher = file_regexp.matcher(file_name);
2277: if (matcher.matches()) {
2278: if (mRequestState.hasUploadedFile(file_name)
2279: && !result.contains(file_name)
2280: && (null == pattern || pattern.matcher(
2281: file_name).matches())) {
2282: result.add(file_name);
2283: }
2284: }
2285: }
2286:
2287: }
2288:
2289: return result;
2290: }
2291:
2292: ArrayList<String> getUploadedFileNames() throws EngineException {
2293: ArrayList<String> result = new ArrayList<String>();
2294: String submission_name = getSubmission();
2295: if (null == submission_name) {
2296: return result;
2297: }
2298:
2299: Submission submission = mElementInfo
2300: .getSubmission(submission_name);
2301: if (null == submission) {
2302: return result;
2303: }
2304:
2305: Collection<String> file_names = submission.getFileNames();
2306: for (String file_name : file_names) {
2307: if (mRequestState.hasUploadedFile(file_name)) {
2308: result.add(file_name);
2309: }
2310: }
2311:
2312: return result;
2313: }
2314:
2315: boolean hasUploadedFile(String name) throws EngineException {
2316: assert name != null;
2317: assert name.length() > 0;
2318:
2319: validateFile(name);
2320:
2321: String submission = getSubmission();
2322: if (null == submission) {
2323: return false;
2324: }
2325:
2326: return mRequestState.hasUploadedFile(name);
2327: }
2328:
2329: boolean isFileEmpty(String name) throws EngineException {
2330: assert name != null;
2331: assert name.length() > 0;
2332:
2333: UploadedFile file = getUploadedFile(name);
2334: return null == file || null == file.getFile()
2335: || 0 == file.getFile().length();
2336: }
2337:
2338: UploadedFile getUploadedFile(String name) throws EngineException {
2339: assert name != null;
2340: assert name.length() > 0;
2341:
2342: validateFile(name);
2343:
2344: String submission = getSubmission();
2345: if (null == submission) {
2346: return null;
2347: }
2348:
2349: return mRequestState.getUploadedFile(name);
2350: }
2351:
2352: UploadedFile[] getUploadedFiles(String name) throws EngineException {
2353: assert name != null;
2354: assert name.length() > 0;
2355:
2356: validateFile(name);
2357:
2358: String submission = getSubmission();
2359: if (null == submission) {
2360: return null;
2361: }
2362:
2363: return mRequestState.getUploadedFiles(name);
2364: }
2365:
2366: void setOutputValues(String name, String[] values) {
2367: assert name != null;
2368: assert name.length() > 0;
2369: assert values != null;
2370:
2371: mOutputs.put(name, values);
2372: fireOutputValueSet(name, values);
2373: }
2374:
2375: void setAutomatedOutputValues(String name, String[] values) {
2376: mOutputs.putFallback(name, values);
2377:
2378: fireAutomatedOutputValueSet(name, values);
2379: }
2380:
2381: void clearOutputValue(String name) {
2382: assert name != null;
2383: assert name.length() > 0;
2384:
2385: // clearing the output value instead of removing it, this prevents
2386: // later automated processing to fill it in again
2387: mOutputs.put(name, null);
2388: fireOutputValueCleared(name);
2389: }
2390:
2391: void clearAutomatedOutputValue(String name) {
2392: // clearing the output value instead of removing it, this prevents
2393: // later automated processing to fill it in again
2394: mOutputs.putFallback(name, null);
2395: fireAutomatedOutputValueCleared(name);
2396: }
2397:
2398: void addOutputListener(OutputListener listener) {
2399: if (null == mOutputListeners) {
2400: mOutputListeners = new ArrayList<OutputListener>();
2401: }
2402:
2403: mOutputListeners.add(listener);
2404: }
2405:
2406: void removeOutputListener(OutputListener listener) {
2407: mOutputListeners.remove(listener);
2408: }
2409:
2410: void fireOutputValueSet(String name, String[] values) {
2411: if (null == mOutputListeners) {
2412: return;
2413: }
2414:
2415: for (OutputListener listener : mOutputListeners) {
2416: listener.outputValueSet(name, values);
2417: }
2418: }
2419:
2420: void fireOutputValueCleared(String name) {
2421: if (null == mOutputListeners) {
2422: return;
2423: }
2424:
2425: for (OutputListener listener : mOutputListeners) {
2426: listener.outputValueCleared(name);
2427: }
2428: }
2429:
2430: void fireAutomatedOutputValueSet(String name, String[] values) {
2431: if (null == mOutputListeners) {
2432: return;
2433: }
2434:
2435: for (OutputListener listener : mOutputListeners) {
2436: listener.automatedOutputValueSet(name, values);
2437: }
2438: }
2439:
2440: void fireAutomatedOutputValueCleared(String name) {
2441: if (null == mOutputListeners) {
2442: return;
2443: }
2444:
2445: for (OutputListener listener : mOutputListeners) {
2446: listener.automatedOutputValueCleared(name);
2447: }
2448: }
2449:
2450: void addOutcookieListener(OutcookieListener listener) {
2451: if (null == mOutcookieListeners) {
2452: mOutcookieListeners = new ArrayList<OutcookieListener>();
2453: }
2454:
2455: mOutcookieListeners.add(listener);
2456: }
2457:
2458: void removeOutcookieListener(OutcookieListener listener) {
2459: mOutcookieListeners.remove(listener);
2460: }
2461:
2462: void fireOutcookieSet(Cookie cookie) {
2463: if (null == mOutcookieListeners) {
2464: return;
2465: }
2466:
2467: for (OutcookieListener listener : mOutcookieListeners) {
2468: listener.outcookieSet(cookie);
2469: }
2470: }
2471:
2472: void child() throws EngineException {
2473: throw new ChildTriggeredException(null, null);
2474: }
2475:
2476: void defer() throws EngineException {
2477: throw new DeferException();
2478: }
2479:
2480: void forward(String url) throws EngineException {
2481: throw new ForwardException(url);
2482: }
2483:
2484: void redirect(String url) {
2485: throw new RedirectException(url);
2486: }
2487:
2488: boolean duringStepBack() {
2489: return mSteppedBack;
2490: }
2491:
2492: void exit(String name) throws EngineException {
2493: assert name != null;
2494: assert name.length() > 0;
2495:
2496: mElementInfo.validateExitName(name);
2497:
2498: throw new ExitTriggeredException(name);
2499: }
2500:
2501: /**
2502: * Retrieves the inputs values that a child receives when the parent
2503: * delegates the control flow to it. This is based on the current output
2504: * values of the parent element, combined with the global variables
2505: */
2506: private Map<String, String[]> getChildInputValues(
2507: ElementInfo targetElement) {
2508: Map<String, String[]> inputs = null;
2509:
2510: inputs = mElementState.getTriggerInputs();
2511:
2512: if (null == inputs) {
2513: inputs = mElementState.getRequestParameters();
2514: }
2515:
2516: if (mElementInfo.hasGlobalVars()
2517: && targetElement.hasGlobalVars()) {
2518: String[] input_values_array = null;
2519:
2520: for (Map.Entry<String, String[]> output_entry : mOutputs
2521: .aggregateValues().entrySet()) {
2522: // create automatic data link for global variables
2523: if (mElementInfo.containsGlobalVar(output_entry
2524: .getKey())
2525: && targetElement.containsGlobalVar(output_entry
2526: .getKey())) {
2527: input_values_array = output_entry.getValue();
2528: inputs.put(output_entry.getKey(),
2529: input_values_array);
2530: }
2531: }
2532: }
2533:
2534: return inputs;
2535: }
2536:
2537: /**
2538: * Retrieves the inputs values that an exit receives when it is
2539: * followed. This is based on the current output values of the
2540: * active element.
2541: */
2542: private HashMap<String, String[]> getExitInputValues(
2543: FlowLink flowLink,
2544: Set<Map.Entry<String, String[]>> outputEntries,
2545: ElementInfo target, boolean snapback)
2546: throws EngineException {
2547: HashMap<String, String[]> inputs = new HashMap<String, String[]>();
2548:
2549: // preserve the embedding element's inputs and global vars
2550: if (target.getId().equals(mElementInfo.getId())) {
2551: ElementContext context = this ;
2552: while (context != null
2553: && context.mRequestState.isEmbedded()) {
2554: context = context.mRequestState.getEmbeddingContext()
2555: .getElementContext();
2556: for (String input_name : context.mElementInfo
2557: .getInputNames()) {
2558: if (context.mElementState.hasInputValue(input_name)) {
2559: inputs.put(input_name, context.mElementState
2560: .getInputValues(input_name));
2561: }
2562: }
2563: for (String globalvar_name : context.mElementInfo
2564: .getGlobalVarNames()) {
2565: if (context.mElementState
2566: .hasInputValue(globalvar_name)) {
2567: inputs
2568: .put(
2569: globalvar_name,
2570: context.mElementState
2571: .getInputValues(globalvar_name));
2572: }
2573: }
2574: }
2575: }
2576:
2577: if (mElementInfo.hasSnapbackDataLinks()
2578: || mElementInfo.hasDataLink(target)
2579: || (mElementInfo.hasGlobalVars() && target
2580: .hasGlobalVars())) {
2581: HashMap<String, String[]> dest_input_candidates = new HashMap<String, String[]>();
2582:
2583: // if the exit is reflective, preserve the input values that have
2584: // identically named output values
2585: if (target == mElementInfo) {
2586: Collection<String> input_names = mElementInfo
2587: .getInputNames();
2588: Collection<String> output_names = mElementInfo
2589: .getOutputNames();
2590: Iterator<String> input_names_it = input_names
2591: .iterator();
2592: String input_name = null;
2593: String[] input_values = null;
2594: while (input_names_it.hasNext()) {
2595: input_name = input_names_it.next();
2596:
2597: if (output_names.contains(input_name)) {
2598: input_values = getInputValues(input_name);
2599: if (input_values != null) {
2600: dest_input_candidates.put(input_name,
2601: input_values);
2602: }
2603: }
2604: }
2605: }
2606:
2607: // add the global default values
2608: GlobalVar globalvar_data = null;
2609:
2610: for (Map.Entry<String, GlobalVar> globalvar_entry : mElementInfo
2611: .getGlobalVarEntries()) {
2612: globalvar_data = globalvar_entry.getValue();
2613: if (globalvar_data != null
2614: && globalvar_data.getDefaultValues() != null) {
2615: dest_input_candidates.put(globalvar_entry.getKey(),
2616: globalvar_data.getDefaultValues());
2617: }
2618: }
2619:
2620: // add the output values
2621: String[] output_values_array = null;
2622:
2623: for (Map.Entry<String, String[]> output_entry : outputEntries) {
2624: output_values_array = output_entry.getValue();
2625: dest_input_candidates.put(output_entry.getKey(),
2626: output_values_array);
2627: }
2628:
2629: // process the exit input value candidates
2630: Collection<String> dest_input_names = null;
2631:
2632: GlobalVar globalvar_source = null;
2633: GlobalVar globalvar_target = null;
2634:
2635: for (String candidate : dest_input_candidates.keySet()) {
2636: if (!mElementInfo.containsDepartureVar(candidate)) {
2637: // create automatic data link for global variables
2638: if (mElementInfo.containsGlobalVar(candidate)
2639: && target.containsGlobalVar(candidate)) {
2640: globalvar_source = mElementInfo
2641: .getGlobalVarInfo(candidate);
2642: globalvar_target = target
2643: .getGlobalVarInfo(candidate);
2644:
2645: // only create the link if the global vars are in the
2646: // same group scope
2647: if (globalvar_source.getGroupId() == globalvar_target
2648: .getGroupId()) {
2649: inputs.put(candidate, dest_input_candidates
2650: .get(candidate));
2651: }
2652: }
2653:
2654: // translate outputs to inputs through a possible data link
2655: dest_input_names = mElementInfo.getDataLinkInputs(
2656: candidate, target, snapback, flowLink);
2657: if (dest_input_names != null) {
2658: for (String dest_input_name : dest_input_names) {
2659: inputs.put(dest_input_name,
2660: dest_input_candidates
2661: .get(candidate));
2662: }
2663: }
2664: }
2665: }
2666: }
2667:
2668: return inputs;
2669: }
2670:
2671: private void appendTargetAndPathinfo(StringBuilder url,
2672: String targetUrl, String pathinfo) {
2673: url.append(targetUrl);
2674:
2675: // append the optional pathinfo
2676: if (pathinfo != null && pathinfo.length() > 0) {
2677: // ensure that the pathinfo is prefixed with a /
2678: if (url.charAt(url.length() - 1) != '/') {
2679: url.append("/");
2680: }
2681: url.append(StringUtils.stripFromFront(pathinfo, "/"));
2682: }
2683: }
2684:
2685: private String getExitUrl(FlowLink flowlink, String pathInfo)
2686: throws EngineException {
2687: assert flowlink != null;
2688:
2689: String url = null;
2690: String pathinfo = null;
2691:
2692: // obtain the declared flowlink target element and determine what the
2693: // actual target element is according to the inheritance status
2694: ElementInfo flowlink_target = flowlink
2695: .getExitTarget(mRequestState);
2696: ElementInfo context_target = null;
2697: if (mElementState.inInheritanceStructure()
2698: && !flowlink.cancelInheritance()) {
2699: context_target = mRequestState.getTarget();
2700: } else {
2701: context_target = flowlink_target;
2702: }
2703: url = context_target.getUrl();
2704:
2705: // if the element defined no url and the flowlink target points to the element
2706: // itself when it's embedded, go up the hierarchy of embedded elements
2707: // to grab the first defined element url
2708: if (null == url) {
2709: if (!mRequestState.isEmbedded()
2710: && !flowlink_target.getId().equals(
2711: mElementInfo.getId())) {
2712: throw new ExitTargetUrlMissingException(mElementInfo
2713: .getDeclarationName(), flowlink.getExitName(),
2714: context_target.getDeclarationName());
2715: }
2716:
2717: ElementContext context = this ;
2718: while (null == url && context != null
2719: && context.mRequestState.isEmbedded()) {
2720: context = context.mRequestState.getEmbeddingContext()
2721: .getElementContext();
2722: if (context.getElementInfo().isPathInfoUsed()) {
2723: pathinfo = context.mRequestState.getElementState()
2724: .getPathInfo();
2725: } else {
2726: pathinfo = null;
2727: }
2728: if (context.mElementState.inInheritanceStructure()) {
2729: url = context.mRequestState.getTarget().getUrl();
2730: } else {
2731: url = context.mElementInfo.getUrl();
2732: }
2733: }
2734: }
2735:
2736: // apply a forced pathinfo
2737: if (pathInfo != null && pathInfo.length() > 0) {
2738: pathinfo = pathInfo;
2739: }
2740:
2741: // construct the correct servlet path and url that points to the
2742: // target child element, or the current element if there are no children
2743: StringBuilder url_buffer = new StringBuilder(mRequestState
2744: .getGateUrl());
2745: appendTargetAndPathinfo(url_buffer, url, pathinfo);
2746: return url_buffer.toString();
2747: }
2748:
2749: private Map<String, String[]> overrideOutputValues(
2750: Map<String, String[]> outputValueMap, String[] outputValues)
2751: throws EngineException {
2752: if (null == outputValues || 0 == outputValues.length) {
2753: return outputValueMap;
2754: }
2755:
2756: Map<String, String[]> outputs = new HashMap<String, String[]>(
2757: outputValueMap);
2758: // store the output overrides
2759: for (int i = 0; i < outputValues.length; i += 2) {
2760: outputs.put(outputValues[i],
2761: new String[] { outputValues[i + 1] });
2762: }
2763:
2764: return outputs;
2765: }
2766:
2767: private Map<String, String[]> getExitInputValues(FlowLink flowLink,
2768: ElementInfo target, boolean snapback,
2769: Map<String, String[]> outputValueMap, String[] outputValues)
2770: throws EngineException {
2771: // override current output values
2772: Map<String, String[]> overridden_outputs = overrideOutputValues(
2773: outputValueMap, outputValues);
2774:
2775: // construct the exit input parameters
2776: return getExitInputValues(flowLink, overridden_outputs
2777: .entrySet(), target, snapback);
2778: }
2779:
2780: private FlowState _getExitParameters(FlowLink flowlink,
2781: ElementInfo contextTarget,
2782: Map<String, String[]> outputValueMap, String[] outputValues) {
2783: FlowState state = new FlowState();
2784:
2785: // construct the exit input parameters
2786: Map<String, String[]> inputs = getExitInputValues(flowlink,
2787: flowlink.getTarget(), flowlink.isSnapback(),
2788: outputValueMap, outputValues);
2789:
2790: // Create or preserve the request parameters that were initially send to the child element
2791: // this permits completely seperate processing of any other parameters.
2792: // Maintain a stack of successful parent elements.
2793: if (mElementState.inInheritanceStructure()
2794: && !flowlink.cancelInheritance()) {
2795: state.putParameter(ReservedParameters.CHILDREQUEST,
2796: getEncodedChildRequest());
2797:
2798: // preserve the trigger list
2799: List<TriggerContext> new_trigger_context = mElementState
2800: .cloneTriggerList();
2801: new_trigger_context.add(TriggerContext.generateExitTrigger(
2802: mElementInfo, flowlink.getExitName(), inputs));
2803:
2804: state.putParameter(ReservedParameters.TRIGGERLIST,
2805: TriggerListEncoder.encode(new_trigger_context));
2806: } else {
2807: // construct the exit input parameters
2808: state.setParameters(inputs);
2809: }
2810:
2811: if (!flowlink.cancelContinuations()) {
2812: // Preserve the continuation id if a continuation context is active
2813: // and the exit goes back to the same element
2814: if (mElementInfo == flowlink.getTarget()) {
2815: String continuation_id = ContinuationContext
2816: .getActiveContextId();
2817: if (continuation_id != null) {
2818: state.putParameter(ReservedParameters.CONTID,
2819: continuation_id);
2820: }
2821: }
2822: }
2823:
2824: return state;
2825: }
2826:
2827: CharSequenceDeferred getExitFormUrl(String name, String pathinfo)
2828: throws EngineException {
2829: assert name != null;
2830: assert name.length() > 0;
2831:
2832: mElementInfo.validateExitName(name);
2833:
2834: FlowLink flowlink = null;
2835: flowlink = mElementInfo.getFlowLink(name);
2836: if (null == flowlink) {
2837: throw new ExitNotAttachedException(mElement
2838: .getElementInfo().getDeclarationName(), name);
2839: }
2840:
2841: return _getExitFormUrl(flowlink, pathinfo, mOutputs
2842: .aggregateValues());
2843: }
2844:
2845: private CharSequenceDeferred _getExitFormUrl(FlowLink flowlink,
2846: String pathinfo, Map<String, String[]> outputValueMap)
2847: throws EngineException {
2848: assert flowlink != null;
2849:
2850: ElementInfo flowlink_target = flowlink
2851: .getExitTarget(mRequestState);
2852:
2853: StateStore state_store = flowlink_target.getStateStore();
2854:
2855: // process the pathinfo mappings
2856: if (null == pathinfo && flowlink_target.isPathInfoUsed()) {
2857: FlowState state = _getExitParameters(flowlink,
2858: flowlink_target, outputValueMap, null);
2859: pathinfo = handlePathInfoMapping(flowlink_target, state,
2860: pathinfo);
2861: }
2862:
2863: return new CharSequenceFormUrl(state_store, getExitUrl(
2864: flowlink, pathinfo));
2865: }
2866:
2867: CharSequenceDeferred getExitFormParameters(String name,
2868: String[] outputValues) throws EngineException {
2869: assert name != null;
2870: assert name.length() > 0;
2871: assert outputValues == null || outputValues.length % 2 == 0;
2872:
2873: mElementInfo.validateExitName(name);
2874:
2875: FlowLink flowlink = null;
2876: flowlink = mElementInfo.getFlowLink(name);
2877: if (null == flowlink) {
2878: throw new ExitNotAttachedException(mElement
2879: .getElementInfo().getDeclarationName(), name);
2880: }
2881:
2882: return _getExitFormParameters(flowlink, mOutputs
2883: .aggregateValues(), outputValues);
2884: }
2885:
2886: CharSequenceDeferred getExitFormParametersJavascript(String name,
2887: String[] outputValues) throws EngineException {
2888: assert name != null;
2889: assert name.length() > 0;
2890: assert outputValues == null || outputValues.length % 2 == 0;
2891:
2892: mElementInfo.validateExitName(name);
2893:
2894: FlowLink flowlink = null;
2895: flowlink = mElementInfo.getFlowLink(name);
2896: if (null == flowlink) {
2897: throw new ExitNotAttachedException(mElement
2898: .getElementInfo().getDeclarationName(), name);
2899: }
2900:
2901: return _getExitFormParametersJavascript(flowlink, mOutputs
2902: .aggregateValues(), outputValues);
2903: }
2904:
2905: private CharSequenceDeferred _getExitFormParameters(
2906: FlowLink flowlink, Map<String, String[]> outputValueMap,
2907: String[] outputValues) throws EngineException {
2908: assert flowlink != null;
2909:
2910: ElementInfo flowlink_target = flowlink
2911: .getExitTarget(mRequestState);
2912: FlowState state = _getExitParameters(flowlink, flowlink_target,
2913: outputValueMap, outputValues);
2914: return new CharSequenceFormState(flowlink_target
2915: .getStateStore(), state, FormStateType.PARAMS);
2916: }
2917:
2918: private CharSequenceDeferred _getExitFormParametersJavascript(
2919: FlowLink flowlink, Map<String, String[]> outputValueMap,
2920: String[] outputValues) throws EngineException {
2921: assert flowlink != null;
2922:
2923: ElementInfo flowlink_target = flowlink
2924: .getExitTarget(mRequestState);
2925: FlowState state = _getExitParameters(flowlink, flowlink_target,
2926: outputValueMap, outputValues);
2927: return new CharSequenceFormState(flowlink_target
2928: .getStateStore(), state, FormStateType.JAVASCRIPT);
2929: }
2930:
2931: CharSequenceDeferred getExitQueryUrl(String name, String pathinfo,
2932: String[] outputValues) throws EngineException {
2933: assert name != null;
2934: assert name.length() > 0;
2935: assert outputValues == null || outputValues.length % 2 == 0;
2936:
2937: mElementInfo.validateExitName(name);
2938:
2939: FlowLink flowlink = null;
2940: flowlink = mElementInfo.getFlowLink(name);
2941: if (null == flowlink) {
2942: throw new ExitNotAttachedException(mElement
2943: .getElementInfo().getDeclarationName(), name);
2944: }
2945:
2946: return _getExitQueryUrl(flowlink, pathinfo, mOutputs
2947: .aggregateValues(), outputValues);
2948: }
2949:
2950: private CharSequenceDeferred _getExitQueryUrl(FlowLink flowlink,
2951: String pathinfo, Map<String, String[]> outputValueMap,
2952: String[] outputValues) throws EngineException {
2953: assert flowlink != null;
2954:
2955: ElementInfo flowlink_target = flowlink
2956: .getExitTarget(mRequestState);
2957:
2958: // process the exit url query parameters
2959: StateStore state_store = flowlink_target.getStateStore();
2960: FlowState state = _getExitParameters(flowlink, flowlink_target,
2961: outputValueMap, outputValues);
2962:
2963: // process the pathinfo mappings
2964: if (null == pathinfo && flowlink_target.isPathInfoUsed()) {
2965: pathinfo = handlePathInfoMapping(flowlink_target, state,
2966: pathinfo);
2967: }
2968:
2969: return new CharSequenceQueryUrl(state_store, getExitUrl(
2970: flowlink, pathinfo), state, mElementInfo, "exit",
2971: flowlink.getExitName());
2972: }
2973:
2974: private String handlePathInfoMapping(ElementInfo flowlinkTarget,
2975: FlowState state, String pathinfo) {
2976: Map<String, String[]> parameters = state.getParameters();
2977:
2978: mapping: for (PathInfoMapping mapping : flowlinkTarget
2979: .getPathInfoMappings()) {
2980: if (parameters.keySet().containsAll(mapping.getInputs())) {
2981: Iterator<String> inputs_it = mapping.getInputs()
2982: .iterator();
2983:
2984: StringBuilder builder = new StringBuilder();
2985: String input_name;
2986: String[] input_value;
2987: for (PathInfoMappingSegment segment : mapping
2988: .getSegments()) {
2989: if (segment.isRegexp()) {
2990: if (!inputs_it.hasNext()) {
2991: continue mapping;
2992: }
2993:
2994: input_name = inputs_it.next();
2995:
2996: // ensure that the input has only got one value
2997: input_value = parameters.get(input_name);
2998: if (null == input_value
2999: || input_value.length != 1) {
3000: continue mapping;
3001: }
3002:
3003: // ensure that the input value corresponds to the
3004: // regexp pattern for it
3005: Matcher matcher = segment.getPattern().matcher(
3006: input_value[0]);
3007: if (!matcher.matches()) {
3008: continue mapping;
3009: }
3010:
3011: // add the url-encoded input value to the pathinfo
3012: builder.append(StringUtils
3013: .encodeUrl(input_value[0]));
3014: } else {
3015: builder.append(segment.getValue());
3016: }
3017: }
3018:
3019: // remove the input parameters that are handled by the pathinfo
3020: for (String input : mapping.getInputs()) {
3021: parameters.remove(input);
3022: }
3023:
3024: // build the new pathinfo
3025: return builder.toString();
3026: }
3027: }
3028:
3029: return null;
3030: }
3031:
3032: void setExitQuery(Template template, String name, String pathinfo,
3033: String[] outputValues) throws TemplateException,
3034: EngineException {
3035: template.setValue(PREFIX_EXIT_QUERY + name, getExitQueryUrl(
3036: name, pathinfo, outputValues).encoder(
3037: EncoderHtml.getInstance()));
3038: }
3039:
3040: void setExitForm(Template template, String name, String pathinfo,
3041: String[] outputValues) throws TemplateException,
3042: EngineException {
3043: template.setValue(PREFIX_EXIT_FORM + name, getExitFormUrl(name,
3044: pathinfo).encoder(EncoderHtml.getInstance()));
3045: String exit_javascript = PREFIX_EXIT_PARAMSJS + name;
3046: if (template.hasValueId(exit_javascript)) {
3047: template.setValue(exit_javascript, getExitFormParameters(
3048: name, outputValues));
3049: } else {
3050: template.setValue(PREFIX_EXIT_PARAMS + name,
3051: getExitFormParameters(name, outputValues));
3052: }
3053: }
3054:
3055: Collection<String> selectParameter(Template template, String name,
3056: String[] values) {
3057: assert name != null;
3058: assert name.length() > 0;
3059:
3060: BeanHandler bean_handler = template.getBeanHandler();
3061: if (null == bean_handler) {
3062: return Collections.EMPTY_LIST;
3063: }
3064: FormBuilder form_builder = bean_handler.getFormBuilder();
3065: if (null == form_builder) {
3066: return Collections.EMPTY_LIST;
3067: }
3068:
3069: return form_builder.selectParameter(template, name, values);
3070: }
3071:
3072: void generateForm(Template template, Object beanInstance,
3073: String prefix) throws EngineException {
3074: BeanHandler bean_handler = template.getBeanHandler();
3075: if (null == bean_handler) {
3076: return;
3077: }
3078: FormBuilder form_builder = bean_handler.getFormBuilder();
3079: if (null == form_builder) {
3080: return;
3081: }
3082: try {
3083: form_builder.removeForm(template, beanInstance.getClass(),
3084: prefix);
3085: form_builder.generateForm(template, beanInstance, null,
3086: prefix);
3087: } catch (BeanUtilsException e) {
3088: throw new EngineException(e);
3089: }
3090: }
3091:
3092: void generateEmptyForm(Template template, Class beanClass,
3093: String prefix) throws EngineException {
3094: BeanHandler bean_handler = template.getBeanHandler();
3095: if (null == bean_handler) {
3096: return;
3097: }
3098: FormBuilder form_builder = bean_handler.getFormBuilder();
3099: if (null == form_builder) {
3100: return;
3101: }
3102: try {
3103: form_builder.removeForm(template, beanClass, prefix);
3104: form_builder
3105: .generateForm(template, beanClass, null, prefix);
3106: } catch (BeanUtilsException e) {
3107: throw new EngineException(e);
3108: }
3109: }
3110:
3111: void removeForm(Template template, Class beanClass, String prefix)
3112: throws EngineException {
3113: BeanHandler bean_handler = template.getBeanHandler();
3114: if (null == bean_handler) {
3115: return;
3116: }
3117: FormBuilder form_builder = bean_handler.getFormBuilder();
3118: if (null == form_builder) {
3119: return;
3120: }
3121: try {
3122: form_builder.removeForm(template, beanClass, prefix);
3123: } catch (BeanUtilsException e) {
3124: throw new EngineException(e);
3125: }
3126: }
3127:
3128: private String getContextId() {
3129: if (mContextId != null) {
3130: return mContextId;
3131: }
3132:
3133: synchronized (mElement) {
3134: mContextId = mRequestState.buildContextId();
3135: }
3136:
3137: return mContextId;
3138: }
3139:
3140: private FlowState getSubmissionParameters(String name,
3141: String[] parameterValues,
3142: Set<Map.Entry<String, String[]>> outputEntries) {
3143: FlowState state = new FlowState();
3144:
3145: state.putParameter(ReservedParameters.SUBMISSION, name);
3146:
3147: // add the submission parameters
3148: if (parameterValues != null) {
3149: String parameter_name = null;
3150: String parameter_value = null;
3151: for (int i = 0; i < parameterValues.length; i += 2) {
3152: parameter_name = parameterValues[i];
3153: parameter_value = parameterValues[i + 1];
3154: state.putParameter(parameter_name, parameter_value);
3155: }
3156:
3157: validateParameter(parameter_name);
3158: }
3159:
3160: // Create the submission context parameter
3161: Submission submission = mElementInfo.getSubmission(name);
3162: if (null == submission || Scope.LOCAL == submission.getScope()) {
3163: String submission_context = getContextId();
3164: String target = getElementInfo().getId();
3165: if (!submission_context.equals(target)) {
3166: StringBuilder submission_context_buffer = new StringBuilder(
3167: submission_context);
3168: submission_context_buffer.append("^");
3169: submission_context_buffer.append(target);
3170: submission_context = submission_context_buffer
3171: .toString();
3172: }
3173: try {
3174: state.putParameter(
3175: ReservedParameters.SUBMISSIONCONTEXT, Base64
3176: .encodeToString(submission_context
3177: .getBytes("UTF-8"), false));
3178: } catch (UnsupportedEncodingException e) {
3179: // should never happen
3180: }
3181: }
3182:
3183: // Preserve the continuation ID if a continuation context is active
3184: if (null == submission || !submission.getCancelContinuations()) {
3185: String continuation_id = ContinuationContext
3186: .getActiveContextId();
3187: if (continuation_id != null) {
3188: state.putParameter(ReservedParameters.CONTID,
3189: continuation_id);
3190: }
3191: }
3192:
3193: // create or preserve the request parameters that were initially send to the child element
3194: // this permits completely seperate processing of any other parameters
3195: if (mElementState.inInheritanceStructure()) {
3196: // preserve the original child request
3197: state.putParameter(ReservedParameters.CHILDREQUEST,
3198: getEncodedChildRequest());
3199:
3200: // preserve the trigger list
3201: state.putParameter(ReservedParameters.TRIGGERLIST,
3202: mElementState.encodeTriggerList());
3203: }
3204:
3205: // preserve the embedding element's inputs and global vars
3206: ElementContext context = this ;
3207: while (context != null && context.mRequestState.isEmbedded()) {
3208: context = context.mRequestState.getEmbeddingContext()
3209: .getElementContext();
3210: for (String input_name : context.mElementInfo
3211: .getInputNames()) {
3212: if (context.mElementState.hasInputValue(input_name)) {
3213: state.putSubmissionGlobalInput(input_name,
3214: context.mElementState.getInputValues(
3215: input_name, false));
3216: }
3217: }
3218: for (String globalvar_name : context.mElementInfo
3219: .getGlobalVarNames()) {
3220: if (context.mElementState.hasInputValue(globalvar_name)) {
3221: state.putSubmissionGlobalInput(globalvar_name,
3222: context.mElementState.getInputValues(
3223: globalvar_name, false));
3224: }
3225: }
3226: }
3227:
3228: // preserve the global variables
3229: for (String globalvar_name : mElementInfo.getGlobalVarNames()) {
3230: if (mElementState.hasInputValue(globalvar_name)) {
3231: state.putSubmissionGlobalInput(globalvar_name,
3232: mElementState.getInputValues(globalvar_name,
3233: false));
3234: }
3235: }
3236:
3237: // activate reflective datalinks for global vars
3238: if (outputEntries != null) {
3239: for (Map.Entry<String, String[]> output : outputEntries) {
3240: // global vars
3241: if (mElementInfo.containsGlobalVar(output.getKey())) {
3242: state.putSubmissionGlobalInput(output.getKey(),
3243: output.getValue());
3244: }
3245: }
3246: }
3247:
3248: // add this element's inputs
3249: Map<String, String[]> element_inputs = null;
3250:
3251: // preserve the input values
3252: for (String input_name : mElementInfo.getInputNames()) {
3253: if (mElementState.hasInputValue(input_name)) {
3254: if (null == element_inputs) {
3255: element_inputs = new LinkedHashMap<String, String[]>();
3256: }
3257:
3258: element_inputs.put(input_name, mElementState
3259: .getInputValues(input_name));
3260: }
3261: }
3262:
3263: // merge this element's inputs with its preserved inputs
3264: Map<String, String[]> preserved_inputs = collectPreservedInputs(outputEntries);
3265:
3266: String context_id = getContextId();
3267: if (preserved_inputs != null && preserved_inputs.size() > 0) {
3268: if (null == element_inputs) {
3269: element_inputs = new LinkedHashMap<String, String[]>();
3270: }
3271: element_inputs.putAll(preserved_inputs);
3272: }
3273: state.setSubmissionElementInputs(element_inputs);
3274:
3275: // remember this element's context identifier for when the context inputs are extracted
3276: state.setSubmissionContextId(context_id);
3277:
3278: return state;
3279: }
3280:
3281: private Map<String, String[]> collectPreservedInputs(
3282: Set<Map.Entry<String, String[]>> outputEntries) {
3283: Map<String, String[]> element_inputs = null;
3284:
3285: // activate reflective datalinks for which outputs point to the inputs
3286: if (outputEntries != null) {
3287: for (Map.Entry<String, String[]> output : outputEntries) {
3288: // reflective datalinks
3289: Collection<String> datalink_inputs = mElementInfo
3290: .getDataLinkInputs(output.getKey(),
3291: mElementInfo, false, null);
3292: if (datalink_inputs != null) {
3293: for (String input_name : datalink_inputs) {
3294: if (null == element_inputs) {
3295: element_inputs = new LinkedHashMap<String, String[]>();
3296: }
3297:
3298: element_inputs.put(input_name, output
3299: .getValue());
3300: }
3301: }
3302: }
3303: }
3304:
3305: return element_inputs;
3306: }
3307:
3308: private String getSubmissionUrl(String pathInfo) {
3309: String url = null;
3310: String pathinfo = null;
3311: if (mElementInfo.isPathInfoUsed()) {
3312: pathinfo = mRequestState.getElementState().getPathInfo();
3313: }
3314: if (mElementState.inInheritanceStructure()) {
3315: url = mRequestState.getTarget().getUrl();
3316: } else {
3317: url = mElementInfo.getUrl();
3318: }
3319:
3320: // if the element defined no url, go up the hierarchy of embedded elements
3321: // to grab the first defined element url
3322: if (null == url) {
3323: if (!mRequestState.isEmbedded()) {
3324: if (mElementState.inInheritanceStructure()) {
3325: throw new SubmissionInheritanceUrlMissingException(
3326: mRequestState.getTarget()
3327: .getDeclarationName(), mElementInfo
3328: .getDeclarationName());
3329: } else {
3330: throw new SubmissionUrlMissingException(
3331: mElementInfo.getDeclarationName());
3332: }
3333: }
3334: ElementContext context = this ;
3335: while (null == url && context != null
3336: && context.mRequestState.isEmbedded()) {
3337: context = context.mRequestState.getEmbeddingContext()
3338: .getElementContext();
3339: if (context.getElementInfo().isPathInfoUsed()) {
3340: pathinfo = context.mRequestState.getElementState()
3341: .getPathInfo();
3342: } else {
3343: pathinfo = null;
3344: }
3345: if (context.mElementState.inInheritanceStructure()) {
3346: url = context.mRequestState.getTarget().getUrl();
3347: } else {
3348: url = context.mElementInfo.getUrl();
3349: }
3350: }
3351: }
3352:
3353: // apply a forced pathinfo
3354: if (pathInfo != null && pathInfo.length() > 0) {
3355: pathinfo = pathInfo;
3356: }
3357:
3358: // construct the correct servlet path and url that points to the
3359: // target child element, or the current element if there are no children
3360: StringBuilder url_buffer = new StringBuilder(mRequestState
3361: .getGateUrl());
3362: appendTargetAndPathinfo(url_buffer, url, pathinfo);
3363: return url_buffer.toString();
3364: }
3365:
3366: private CharSequenceDeferred _getSubmissionQueryUrl(String name,
3367: String pathinfo, String[] parameterValues,
3368: Set<Map.Entry<String, String[]>> outputEntries)
3369: throws EngineException {
3370: StateStore state_store = mElementInfo.getStateStore();
3371: FlowState state = getSubmissionParameters(name,
3372: parameterValues, outputEntries);
3373: return new CharSequenceQueryUrl(state_store,
3374: getSubmissionUrl(pathinfo), state, mElementInfo,
3375: "submission", name);
3376: }
3377:
3378: CharSequenceDeferred getSubmissionQueryUrl(String name,
3379: String pathinfo, String[] parameterValues)
3380: throws EngineException {
3381: assert name != null;
3382: assert name.length() > 0;
3383: assert parameterValues == null
3384: || parameterValues.length % 2 == 0;
3385:
3386: mElementInfo.validateSubmissionName(name);
3387:
3388: return _getSubmissionQueryUrl(name, pathinfo, parameterValues,
3389: mOutputs.aggregateValues().entrySet());
3390: }
3391:
3392: CharSequenceDeferred getSubmissionFormUrl(String pathinfo)
3393: throws EngineException {
3394: return new CharSequenceFormUrl(mElementInfo.getStateStore(),
3395: getSubmissionUrl(pathinfo));
3396: }
3397:
3398: CharSequenceDeferred getSubmissionFormParameters(String name,
3399: String[] parameterValues) throws EngineException {
3400: assert name != null;
3401: assert name.length() > 0;
3402: assert parameterValues == null
3403: || parameterValues.length % 2 == 0;
3404:
3405: mElementInfo.validateSubmissionName(name);
3406:
3407: return _getSubmissionFormParameters(name, parameterValues,
3408: mOutputs.aggregateValues().entrySet());
3409: }
3410:
3411: CharSequenceDeferred getSubmissionFormParametersJavascript(
3412: String name, String[] parameterValues)
3413: throws EngineException {
3414: assert name != null;
3415: assert name.length() > 0;
3416: assert parameterValues == null
3417: || parameterValues.length % 2 == 0;
3418:
3419: mElementInfo.validateSubmissionName(name);
3420:
3421: return _getSubmissionFormParametersJavascript(name,
3422: parameterValues, mOutputs.aggregateValues().entrySet());
3423: }
3424:
3425: private CharSequenceDeferred _getSubmissionFormParameters(
3426: String name, String[] parameterValues,
3427: Set<Map.Entry<String, String[]>> outputEntries)
3428: throws EngineException {
3429: FlowState state = getSubmissionParameters(name,
3430: parameterValues, outputEntries);
3431: return new CharSequenceFormState(mElementInfo.getStateStore(),
3432: state, FormStateType.PARAMS);
3433: }
3434:
3435: private CharSequenceDeferred _getSubmissionFormParametersJavascript(
3436: String name, String[] parameterValues,
3437: Set<Map.Entry<String, String[]>> outputEntries)
3438: throws EngineException {
3439: FlowState state = getSubmissionParameters(name,
3440: parameterValues, outputEntries);
3441: return new CharSequenceFormState(mElementInfo.getStateStore(),
3442: state, FormStateType.JAVASCRIPT);
3443: }
3444:
3445: void setSubmissionQuery(Template template, String name,
3446: String pathinfo, String[] parameterValues)
3447: throws TemplateException, EngineException {
3448: template.setValue(PREFIX_SUBMISSION_QUERY + name,
3449: getSubmissionQueryUrl(name, pathinfo, parameterValues)
3450: .encoder(EncoderHtml.getInstance()));
3451: }
3452:
3453: void setSubmissionForm(Template template, String name,
3454: String pathinfo, String[] parameterValues)
3455: throws TemplateException, EngineException {
3456: template.setValue(PREFIX_SUBMISSION_FORM + name,
3457: getSubmissionFormUrl(pathinfo).encoder(
3458: EncoderHtml.getInstance()));
3459: String submission_javascript = PREFIX_SUBMISSION_PARAMSJS
3460: + name;
3461: if (template.hasValueId(submission_javascript)) {
3462: template.setValue(submission_javascript,
3463: getSubmissionFormParametersJavascript(name,
3464: parameterValues));
3465: } else {
3466: template.setValue(PREFIX_SUBMISSION_PARAMS + name,
3467: getSubmissionFormParameters(name, parameterValues));
3468: }
3469: }
3470:
3471: Collection<String> selectSubmissionParameter(Template template,
3472: String name, String[] values) {
3473: return selectParameter(template, PREFIX_PARAM + name, values);
3474: }
3475:
3476: void setSubmissionBean(Template template, Object beanInstance)
3477: throws TemplateException, EngineException {
3478: setSubmissionBean(template, beanInstance, true);
3479: }
3480:
3481: void setSubmissionBean(Template template, Object beanInstance,
3482: boolean encode) throws TemplateException, EngineException {
3483: template.setBean(beanInstance, PREFIX_PARAM, encode);
3484: }
3485:
3486: void removeSubmissionBean(Template template, Object beanInstance)
3487: throws TemplateException, EngineException {
3488: template.removeBean(beanInstance, PREFIX_PARAM);
3489: }
3490:
3491: private <BeanType> BeanType _getSubmissionBean(
3492: Submission submission, Class<BeanType> beanClass,
3493: String prefix) throws EngineException {
3494: assert submission != null;
3495: assert beanClass != null;
3496:
3497: BeanType bean_instance = getBeanInstance(beanClass);
3498:
3499: try {
3500: HashMap<String, PropertyDescriptor> bean_properties = BeanUtils
3501: .getUppercasedBeanProperties(beanClass);
3502:
3503: String[] parameter_values = null;
3504:
3505: for (String parameter_name : submission.getParameterNames()) {
3506: if (mElementState
3507: .hasRequestParameterValue(parameter_name)) {
3508: parameter_values = mElementState
3509: .getRequestParameterValues(parameter_name);
3510: if (parameter_values != null
3511: && parameter_values.length > 0) {
3512: BeanUtils.setUppercasedBeanProperty(
3513: parameter_name, parameter_values,
3514: prefix, bean_properties, bean_instance,
3515: null);
3516: }
3517: }
3518: }
3519:
3520: for (Pattern parameter_regexp : submission
3521: .getParameterRegexps()) {
3522: for (String parameter_name : getParameterNames(parameter_regexp
3523: .pattern())) {
3524: if (mElementState
3525: .hasRequestParameterValue(parameter_name)) {
3526: parameter_values = mElementState
3527: .getRequestParameterValues(parameter_name);
3528: if (parameter_values != null
3529: && parameter_values.length > 0) {
3530: BeanUtils.setUppercasedBeanProperty(
3531: parameter_name, parameter_values,
3532: prefix, bean_properties,
3533: bean_instance, null);
3534: }
3535: }
3536: }
3537: }
3538:
3539: for (String uploadedfile_name : getUploadedFileNames()) {
3540: UploadedFile file = getUploadedFile(uploadedfile_name);
3541: BeanUtils.setUppercasedBeanProperty(uploadedfile_name,
3542: file, prefix, bean_properties, bean_instance);
3543: }
3544: } catch (BeanUtilsException e) {
3545: throw new EngineException(e);
3546: }
3547:
3548: return bean_instance;
3549: }
3550:
3551: <BeanType> BeanType getNamedSubmissionBean(String submissionName,
3552: String beanName) throws EngineException {
3553: assert submissionName != null;
3554: assert submissionName.length() > 0;
3555: assert beanName != null;
3556: assert beanName.length() > 0;
3557:
3558: mElementInfo.validateSubmissionName(submissionName);
3559:
3560: if (!hasSubmission(submissionName)) {
3561: return null;
3562: }
3563:
3564: BeanDeclaration bean = mElementInfo.getSubmission(
3565: submissionName).getNamedBean(beanName);
3566: Class<BeanType> bean_class = null;
3567:
3568: try {
3569: bean_class = (Class<BeanType>) Class.forName(bean
3570: .getClassname());
3571: } catch (ClassNotFoundException e) {
3572: throw new NamedSubmissionBeanClassnameErrorException(
3573: mElementInfo.getDeclarationName(), submissionName,
3574: beanName, bean.getClassname(), e);
3575: }
3576:
3577: return _getSubmissionBean(mElementInfo
3578: .getSubmission(submissionName), bean_class, bean
3579: .getPrefix());
3580: }
3581:
3582: <BeanType> BeanType getSubmissionBean(String submissionName,
3583: Class<BeanType> beanClass, String prefix)
3584: throws EngineException {
3585: assert submissionName != null;
3586: assert submissionName.length() > 0;
3587: assert beanClass != null;
3588:
3589: mElementInfo.validateSubmissionName(submissionName);
3590:
3591: if (!hasSubmission(submissionName)) {
3592: return null;
3593: }
3594:
3595: return _getSubmissionBean(mElementInfo
3596: .getSubmission(submissionName), beanClass, prefix);
3597: }
3598:
3599: private void _fillSubmissionBean(Submission submission,
3600: Object bean, String prefix) throws EngineException {
3601: assert submission != null;
3602:
3603: if (null == bean) {
3604: return;
3605: }
3606:
3607: try {
3608: HashMap<String, PropertyDescriptor> bean_properties = BeanUtils
3609: .getUppercasedBeanProperties(bean.getClass());
3610: String[] parameter_values = null;
3611:
3612: Object empty_bean = null;
3613:
3614: // handle regular parameters
3615: for (String parameter_name : submission.getParameterNames()) {
3616: parameter_values = mElementState
3617: .getRequestParameterValues(parameter_name);
3618: if (null == empty_bean
3619: && (null == parameter_values || 0 == parameter_values[0]
3620: .length())) {
3621: try {
3622: empty_bean = bean.getClass().newInstance();
3623: } catch (InstantiationException e) {
3624: throw new EngineException(
3625: "Unexpected error while invoking the default constructor of the bean with class '"
3626: + bean.getClass().getName()
3627: + "'.", e);
3628: } catch (IllegalAccessException e) {
3629: throw new EngineException(
3630: "No permission to invoke the default constructor of the bean with class '"
3631: + bean.getClass().getName()
3632: + "'.", e);
3633: }
3634: }
3635:
3636: BeanUtils.setUppercasedBeanProperty(parameter_name,
3637: parameter_values, prefix, bean_properties,
3638: bean, empty_bean);
3639: }
3640:
3641: // handle regexp parameters
3642: for (Pattern parameter_regexp : submission
3643: .getParameterRegexps()) {
3644: for (String parameter_name : getParameterNames(parameter_regexp
3645: .pattern())) {
3646: parameter_values = mElementState
3647: .getRequestParameterValues(parameter_name);
3648: if (null == empty_bean
3649: && (null == parameter_values || 0 == parameter_values[0]
3650: .length())) {
3651: try {
3652: empty_bean = bean.getClass().newInstance();
3653: } catch (InstantiationException e) {
3654: throw new EngineException(
3655: "Unexpected error while invoking the default constructor of the bean with class '"
3656: + bean.getClass().getName()
3657: + "'.", e);
3658: } catch (IllegalAccessException e) {
3659: throw new EngineException(
3660: "No permission to invoke the default constructor of the bean with class '"
3661: + bean.getClass().getName()
3662: + "'.", e);
3663: }
3664: }
3665:
3666: BeanUtils.setUppercasedBeanProperty(parameter_name,
3667: parameter_values, prefix, bean_properties,
3668: bean, empty_bean);
3669: }
3670: }
3671:
3672: // automatically handle uploaded files
3673: for (String uploadedfile_name : getUploadedFileNames()) {
3674: UploadedFile file = getUploadedFile(uploadedfile_name);
3675: BeanUtils.setUppercasedBeanProperty(uploadedfile_name,
3676: file, prefix, bean_properties, bean);
3677: }
3678: } catch (BeanUtilsException e) {
3679: throw new EngineException(e);
3680: }
3681: }
3682:
3683: void fillSubmissionBean(String submissionName, Object bean,
3684: String prefix) throws EngineException {
3685: assert submissionName != null;
3686: assert submissionName.length() > 0;
3687:
3688: if (null == bean) {
3689: return;
3690: }
3691:
3692: mElementInfo.validateSubmissionName(submissionName);
3693:
3694: if (!hasSubmission(submissionName)) {
3695: return;
3696: }
3697:
3698: _fillSubmissionBean(mElementInfo.getSubmission(submissionName),
3699: bean, prefix);
3700: }
3701:
3702: <BeanType> BeanType getNamedInputBean(String name)
3703: throws EngineException {
3704: assert name != null;
3705:
3706: mElementInfo.validateInbeanName(name);
3707:
3708: BeanDeclaration input_bean = mElementInfo
3709: .getNamedInbeanInfo(name);
3710: if (null == input_bean) {
3711: input_bean = mElementInfo.getNamedGlobalBeanInfo(name);
3712: }
3713:
3714: Class<BeanType> input_bean_class = null;
3715:
3716: try {
3717: input_bean_class = (Class<BeanType>) Class
3718: .forName(input_bean.getClassname());
3719: } catch (ClassNotFoundException e) {
3720: throw new NamedInbeanClassnameErrorException(mElementInfo
3721: .getDeclarationName(), name, input_bean
3722: .getClassname());
3723: }
3724:
3725: return getInputBean(input_bean_class, input_bean.getPrefix());
3726: }
3727:
3728: <BeanType> BeanType getInputBean(Class<BeanType> beanClass,
3729: String prefix) throws EngineException {
3730: assert beanClass != null;
3731:
3732: BeanType bean_instance = getBeanInstance(beanClass);
3733:
3734: try {
3735: HashMap<String, PropertyDescriptor> bean_properties = BeanUtils
3736: .getUppercasedBeanProperties(beanClass);
3737:
3738: // merge the input and global variable names
3739: Collection<String> input_names = mElementInfo
3740: .getInputNames();
3741: Collection<String> globalvar_names = mElementInfo
3742: .getGlobalVarNames();
3743: ArrayList<String> merged_names = new ArrayList<String>();
3744: merged_names.addAll(input_names);
3745: merged_names.addAll(globalvar_names);
3746:
3747: // process all the possible input names
3748: String[] values = null;
3749:
3750: for (String name : merged_names) {
3751: if (mElementState.hasInputValue(name)) {
3752: values = mElementState.getInputValues(name);
3753: if (values != null && values.length > 0) {
3754: BeanUtils.setUppercasedBeanProperty(name,
3755: values, prefix, bean_properties,
3756: bean_instance, null);
3757: }
3758: }
3759: }
3760: } catch (BeanUtilsException e) {
3761: throw new EngineException(e);
3762: }
3763:
3764: return bean_instance;
3765: }
3766:
3767: void setNamedOutputBean(String name, Object bean)
3768: throws EngineException {
3769: assert name != null;
3770:
3771: mElementInfo.validateOutbeanName(name);
3772:
3773: BeanDeclaration output_bean = mElementInfo
3774: .getNamedOutbeanInfo(name);
3775: if (null == output_bean) {
3776: output_bean = mElementInfo.getNamedGlobalBeanInfo(name);
3777: }
3778:
3779: setOutputBean(bean, output_bean.getPrefix());
3780: }
3781:
3782: void setOutputBean(Object bean, String prefix)
3783: throws EngineException {
3784: if (null == bean)
3785: throw new IllegalArgumentException("bean can't be null.");
3786:
3787: Map<String, String[]> values = getOutputBeanValues(bean,
3788: prefix, null);
3789:
3790: String name;
3791: String[] value;
3792: for (Map.Entry<String, String[]> entry : values.entrySet()) {
3793: name = entry.getKey();
3794: value = entry.getValue();
3795:
3796: setOutputValues(name, value);
3797:
3798: if (mElementState.inInheritanceStructure()
3799: && mElementInfo.containsChildTrigger(name)) {
3800: triggerChild(name, value);
3801: }
3802: }
3803: }
3804:
3805: Map<String, String[]> getOutputBeanValues(Object bean,
3806: String prefix, Collection<String> included)
3807: throws BeanInstanceValuesErrorException {
3808: if (null == bean)
3809: return Collections.EMPTY_MAP;
3810:
3811: Map<String, String[]> values = new LinkedHashMap<String, String[]>();
3812: try {
3813: Constrained constrained = ConstrainedUtils
3814: .makeConstrainedInstance(bean);
3815: ConstrainedProperty constrained_property = null;
3816:
3817: Set<String> merged_names = new LinkedHashSet<String>();
3818:
3819: // handle outputs
3820: Collection<String> output_names = mElementInfo
3821: .getOutputNames();
3822: if (null == included) {
3823: merged_names.addAll(output_names);
3824: } else {
3825: for (String name : output_names) {
3826: if (included.contains(name)) {
3827: merged_names.add(name);
3828: }
3829: }
3830: }
3831:
3832: // handle globals
3833: Collection<String> globalvar_names = mElementInfo
3834: .getGlobalVarNames();
3835: if (null == included) {
3836: merged_names.addAll(globalvar_names);
3837: } else {
3838: for (String name : globalvar_names) {
3839: if (included.contains(name)) {
3840: merged_names.add(name);
3841: }
3842: }
3843: }
3844:
3845: // create the merged array
3846: String[] merged_names_array = new String[merged_names
3847: .size()];
3848: merged_names.toArray(merged_names_array);
3849:
3850: // process all the possible output names
3851: Map<String, Object> property_values = BeanUtils
3852: .getPropertyValues(bean, merged_names_array, null,
3853: prefix);
3854: Object property_value = null;
3855:
3856: for (String property_name : property_values.keySet()) {
3857: property_value = property_values.get(property_name);
3858:
3859: if (property_value != null) {
3860: // get the constrained property if that's appropriate
3861: if (constrained != null) {
3862: if (prefix != null) {
3863: constrained_property = constrained
3864: .getConstrainedProperty(property_name
3865: .substring(prefix.length()));
3866: } else {
3867: constrained_property = constrained
3868: .getConstrainedProperty(property_name);
3869: }
3870: }
3871:
3872: values.put(property_name, getOutputObjectValues(
3873: property_name, property_value,
3874: constrained_property));
3875: }
3876: }
3877: } catch (BeanUtilsException e) {
3878: throw new BeanInstanceValuesErrorException(bean, e);
3879: }
3880: return values;
3881: }
3882:
3883: private <BeanType> BeanType getBeanInstance(
3884: Class<BeanType> beanClass) throws EngineException {
3885: BeanType bean_instance;
3886:
3887: try {
3888: bean_instance = beanClass.newInstance();
3889: } catch (InstantiationException e) {
3890: throw new EngineException(
3891: "Can't instantiate a bean with class '"
3892: + beanClass.getName() + "'.", e);
3893: } catch (IllegalAccessException e) {
3894: throw new EngineException(
3895: "No permission to instantiate a bean with class '"
3896: + beanClass.getName() + "'.", e);
3897: }
3898:
3899: return bean_instance;
3900: }
3901:
3902: void processEmbeddedElement(Template template,
3903: ElementSupport embeddingElement, String elementId,
3904: String differentiator, Object data)
3905: throws TemplateException, EngineException {
3906: // process the embedded elements
3907: if (template.hasFilteredValues(TAG_ELEMENT)) {
3908: List<String[]> element_tags = template
3909: .getFilteredValues(TAG_ELEMENT);
3910: for (String[] captured_groups : element_tags) {
3911: if (null == differentiator) {
3912: if (elementId.equals(captured_groups[3])) {
3913: processEmbeddedElement(captured_groups[0],
3914: template, embeddingElement,
3915: captured_groups[3], null, data);
3916: return;
3917: }
3918: } else {
3919: if (elementId.equals(captured_groups[3])) {
3920: String value_id = captured_groups[1] + ":";
3921:
3922: String differentiator_value_id = value_id
3923: + differentiator;
3924: if (template
3925: .hasValueId(differentiator_value_id)) {
3926: processEmbeddedElement(
3927: differentiator_value_id, template,
3928: embeddingElement, elementId,
3929: differentiator, data);
3930: return;
3931: } else if (template.hasValueId(value_id)) {
3932: processEmbeddedElement(value_id, template,
3933: embeddingElement, elementId,
3934: differentiator, data);
3935: return;
3936: }
3937: }
3938: }
3939: }
3940: }
3941:
3942: throw new EmbeddedElementNotFoundException(elementId);
3943: }
3944:
3945: private void processEmbeddedElement(String valueId,
3946: Template template, ElementSupport embeddingElement,
3947: String elementId, String differentiator, Object data)
3948: throws TemplateException, EngineException {
3949: if (!template.hasValueId(valueId)) {
3950: throw new EmbeddedElementNotFoundException(elementId);
3951: }
3952:
3953: ElementInfo embedded_element = null;
3954: RequestState embedded_state = null;
3955: Response embedded_response = null;
3956:
3957: // try to obtain the embedded element and throw an exception if
3958: // it couldn't be found
3959: embedded_element = mElementInfo.getSite().resolveId(elementId,
3960: mElementInfo);
3961: if (null == embedded_element) {
3962: throw new ElementIdNotFoundException(elementId);
3963: }
3964:
3965: // build the embedded element request parameter by merging
3966: // the current element's request parameters with its input values
3967: // also merge in the state global vars
3968: Map<String, String[]> parameters = new HashMap<String, String[]>(
3969: mElementState.getRequestParameters());
3970: for (Map.Entry<String, String[]> input_entry : mElementState
3971: .getInputEntries()) {
3972: if (!parameters.containsKey(input_entry.getKey())) {
3973: parameters.put(input_entry.getKey(), input_entry
3974: .getValue());
3975: }
3976: }
3977: if (mRequestState.getStateGlobalVars() != null) {
3978: for (Map.Entry<String, String[]> globalvar_entry : mRequestState
3979: .getStateGlobalVars().entrySet()) {
3980: parameters.put(globalvar_entry.getKey(),
3981: globalvar_entry.getValue());
3982: }
3983: }
3984:
3985: // build the request and response objects for the embedded element
3986: // and service the request
3987: EmbeddingContext embedding_context = new EmbeddingContext(this ,
3988: embeddingElement, template, template
3989: .getDefaultValue(valueId), differentiator, data);
3990: embedded_response = mResponse.createEmbeddedResponse(valueId,
3991: differentiator);
3992: embedded_state = RequestState.getEmbeddedInstance(
3993: embedded_response, embedding_context, parameters,
3994: embedded_element);
3995:
3996: embedded_state.service();
3997: embedded_response.close();
3998:
3999: if (embedding_context.getCancelEmbedding()) {
4000: // handle embedding cancellation by throwing a dedicated exception
4001: // that will bubble up to the first embedding element and print
4002: // out the embedded content
4003: throw new CancelEmbeddingTriggeredException(
4004: embedded_response.getEmbeddedContent());
4005: } else {
4006: // set the output of the element to the value in the template
4007: template.setValue(valueId, embedded_response
4008: .getEmbeddedContent());
4009: }
4010: }
4011:
4012: void evaluateExpressionRoleUserTags(List<String> setValues,
4013: Template template, String id) {
4014: if (template.hasFilteredBlocks(TAG_OGNL_ROLEUSER)
4015: || template.hasFilteredBlocks(TAG_MVEL_ROLEUSER)
4016: || template.hasFilteredBlocks(TAG_GROOVY_ROLEUSER)
4017: || template.hasFilteredBlocks(TAG_JANINO_ROLEUSER)) {
4018: RoleUserIdentity identity = (RoleUserIdentity) mRequestState
4019: .getRequestAttribute(Identified.IDENTITY_ATTRIBUTE_NAME);
4020:
4021: if (identity != null) {
4022: RoleUserAttributes attributes = identity
4023: .getAttributes();
4024: HashMap<String, Object> map = new HashMap<String, Object>();
4025: map.put("login", identity.getLogin());
4026: map.put("password", attributes.getPassword());
4027: map.put("userId", attributes.getUserId());
4028: map.put("roles", attributes.getRoles());
4029:
4030: if (template.hasFilteredBlocks(TAG_OGNL_ROLEUSER)) {
4031: String language_id = id;
4032: if (language_id != null) {
4033: language_id = PREFIX_OGNL_ROLEUSER
4034: + language_id;
4035: }
4036: FilteredTagProcessorOgnl
4037: .getInstance()
4038: .processTags(
4039: setValues,
4040: template,
4041: template
4042: .getFilteredBlocks(TAG_OGNL_ROLEUSER),
4043: language_id,
4044: RoleUserAttributes.class, "user",
4045: attributes, map);
4046: }
4047:
4048: if (template.hasFilteredBlocks(TAG_MVEL_ROLEUSER)) {
4049: String language_id = id;
4050: if (language_id != null) {
4051: language_id = PREFIX_MVEL_ROLEUSER
4052: + language_id;
4053: }
4054: FilteredTagProcessorMvel
4055: .getInstance()
4056: .processTags(
4057: setValues,
4058: template,
4059: template
4060: .getFilteredBlocks(TAG_MVEL_ROLEUSER),
4061: language_id,
4062: RoleUserAttributes.class, "user",
4063: attributes, map);
4064: }
4065:
4066: if (template.hasFilteredBlocks(TAG_GROOVY_ROLEUSER)) {
4067: String language_id = id;
4068: if (language_id != null) {
4069: language_id = PREFIX_GROOVY_ROLEUSER
4070: + language_id;
4071: }
4072: FilteredTagProcessorGroovy
4073: .getInstance()
4074: .processTags(
4075: setValues,
4076: template,
4077: template
4078: .getFilteredBlocks(TAG_GROOVY_ROLEUSER),
4079: language_id,
4080: RoleUserAttributes.class, "user",
4081: attributes, map);
4082: }
4083:
4084: if (template.hasFilteredBlocks(TAG_JANINO_ROLEUSER)) {
4085: String language_id = id;
4086: if (language_id != null) {
4087: language_id = PREFIX_JANINO_ROLEUSER
4088: + language_id;
4089: }
4090: FilteredTagProcessorJanino
4091: .getInstance()
4092: .processTags(
4093: setValues,
4094: template,
4095: template
4096: .getFilteredBlocks(TAG_JANINO_ROLEUSER),
4097: language_id,
4098: RoleUserAttributes.class, "user",
4099: attributes, map);
4100: }
4101: }
4102: }
4103: }
4104:
4105: private String getEncodedChildRequest() {
4106: String child_request = null;
4107:
4108: if (mElementState
4109: .hasRequestParameterValue(ReservedParameters.CHILDREQUEST)) {
4110: child_request = mElementState
4111: .getRequestParameter(ReservedParameters.CHILDREQUEST);
4112: } else {
4113: child_request = ChildRequestEncoder.encode(mElementState
4114: .getInheritanceStack().get(0), mRequestState);
4115: }
4116:
4117: return child_request;
4118: }
4119: }
|