/* * Copyright 2001-2008 Geert Bevin <gbevin[remove] at uwyn dot com> * Licensed under the Apache License, Version 2.0 (the "License") * $Id: ElementExecutionState.java 3918 2008-04-14 17:35:35Z gbevin $ */ package com.uwyn.rife.engine; import java.util.*; import com.uwyn.rife.tools.ExceptionUtils; import java.util.logging.Logger; import java.util.regex.Matcher; class ElementExecutionState implements Cloneable { private RequestState mRequestState = null; private RequestMethod mMethod = null; private String mPathInfo = null; private Stack<String> mInheritanceStack = null; private Map<String, String[]> mRequestParameters = null; private Map<String, String[]> mTriggerInputs = null; private Map<String, String[]> mPreservedInputs = null; private Map<String, String[]> mPathInfoInputs = null; private HashSet<String> mNonRequestParameterInputs = null; private List<TriggerContext> mTriggerList = null; private List<TriggerContext> mTriggerListState = null; ElementExecutionState(RequestState requestState) { setRequestState(requestState); if (mRequestState.getRequest() != null) { setMethod(mRequestState.getRequest().getMethod()); } } void setRequestState(RequestState request) { mRequestState = request; } void setPathInfo(String pathInfo) { mPathInfo = pathInfo; clearVirtualInputs(); } String getPathInfo() { return mPathInfo; } void setMethod(RequestMethod method) { assert method != null; mMethod = method; } void setInheritanceStack(Stack<String> inheritanceStack) { mInheritanceStack = inheritanceStack; } Stack<String> getInheritanceStack() { return mInheritanceStack; } void setTriggerInputs(Map<String, String[]> inputs) { mTriggerInputs = inputs; } Map<String, String[]> getTriggerInputs() { return mTriggerInputs; } void setNonRequestParameterInputs(HashSet<String> set) { mNonRequestParameterInputs = set; } boolean isInheritanceTarget() { if (mInheritanceStack != null && 0 == mInheritanceStack.size()) { return true; } return false; } boolean inInheritanceStructure() { if (mInheritanceStack != null && mInheritanceStack.size() > 0) { return true; } return false; } private boolean isNonRequestParameterInput(String name) { if (null == mNonRequestParameterInputs) { return false; } return mNonRequestParameterInputs.contains(name); } void clearVirtualInputs() { mPathInfoInputs = null; mPreservedInputs = null; } private Map<String, String[]> getPreservedInputs() { if (mPreservedInputs != null) { return mPreservedInputs; } Map<String, String[]> result = null; // merges the global preserved inputs with the element's preserved inputs ResultStates preserved = mRequestState.getElementResultStatesRestored(); if (preserved.size() > 0) { // get the global result state ElementResultState global_result_state = preserved.get(""); if (global_result_state != null) { result = global_result_state.getPreservedInputs(); } // merge the element's result state ElementResultState element_result_state = preserved.get(mRequestState.buildContextId()); if (element_result_state != null) { Map<String, String[]> element_inputs_map = element_result_state.getPreservedInputs(); if (null == result) { result = element_inputs_map; } else { result.putAll(element_inputs_map); } } } if (null == result) { result = Collections.EMPTY_MAP; } mPreservedInputs = result; return mPreservedInputs; } private Map<String, String[]> getPathInfoInputs() { if (mPathInfoInputs != null) { return mPathInfoInputs; } if (mRequestState.getTarget().hasPathInfoMappings()) { Map<String, String[]> inputs = new HashMap<String, String[]>(); Matcher matcher; Iterator<String> input_names_it; for (PathInfoMapping mapping : mRequestState.getTarget().getPathInfoMappings()) { matcher = mapping.getRegexp().matcher(mPathInfo); if (matcher.matches()) { input_names_it = mapping.getInputs().iterator(); for (int i = 1; i <= mapping.getInputs().size(); i++) { inputs.put(input_names_it.next(), new String[] {matcher.group(i)}); } break; } } mPathInfoInputs = inputs; } else { mPathInfoInputs = Collections.EMPTY_MAP; } return mPathInfoInputs; } /* * Inputs should only come from a HTTP request in a direct access. * * If inputs are provided through exits, the request is not checked. * * If inputs are provided through inheritance, the request is not checked, * unless the element is the target element. * In this case the original request is restored. However, in the meantime, * values might have been modified higher in parent elements through the * modification of global variables. * Therefore, when inputs are requested in a target element of an inheritance * stack, first the provided inputs are checked and then the original request. */ String[] getInputValues(String name) { return getInputValues(name, true); } String[] getInputValues(String name, boolean usePreservedInputs) { assert name != null; assert name.length() > 0; String[] input_values = null; if (isInheritanceTarget()) { if (mTriggerInputs != null) { input_values = mTriggerInputs.get(name); } if (null == input_values && getPreservedInputs() != null) { input_values = getPreservedInputs().get(name); } if (null == input_values && !isNonRequestParameterInput(name)) { input_values = getRequestParameterValues(name); } // if pathinfo inputs were provided, check them as a last resort if (null == input_values && getPathInfoInputs().size() > 0) { input_values = getPathInfoInputs().get(name); } } else { // try to obtain the input from a previous element // (arrived at the current element through an exit) if (mTriggerInputs != null) { input_values = mTriggerInputs.get(name); } // if no inputs were provided through a previous element, obtain the // values from the request else { if (getPreservedInputs() != null) { input_values = getPreservedInputs().get(name); } if (null == input_values && !isNonRequestParameterInput(name)) { input_values = getRequestParameterValues(name); } // if pathinfo inputs were provided, check them as a last resort if (null == input_values && getPathInfoInputs().size() > 0) { input_values = getPathInfoInputs().get(name); } } } return input_values; } boolean hasInputValue(String name) { return getInputValues(name) != null; } String getInput(String name) { String[] input_value = getInputValues(name); if (null == input_value) { return null; } return input_value[0]; } Set<Map.Entry<String, String[]>> getInputEntries() { Set<Map.Entry<String, String[]>> input_entries = null; if (isInheritanceTarget()) { HashMap<String, String[]> inputs_merge = new HashMap<String, String[]>(); // put all the request parameters in the map inputs_merge.putAll(getRequestParameters()); // remove all the request parameters that don't qualify as inputs if (mNonRequestParameterInputs != null) { for (String non_input_param : mNonRequestParameterInputs) { inputs_merge.remove(non_input_param); } } // put and override the map entries with the element inputs inputs_merge.putAll(mTriggerInputs); // add the preserved inputs if (getPreservedInputs() != null) { inputs_merge.putAll(getPreservedInputs()); } // if pathinfo inputs were provided, add them as a last resort // without overriding the already existing inputs if (getPathInfoInputs().size() > 0) { for (Map.Entry<String, String[]> entry : getPathInfoInputs().entrySet()) { if (!inputs_merge.containsKey(entry.getKey())) { inputs_merge.put(entry.getKey(), entry.getValue()); } } } // get the entries of the map input_entries = inputs_merge.entrySet(); } else { // try to obtain the input entries from a previous element // (arrived at the current element through an exit) if (mTriggerInputs != null) { input_entries = mTriggerInputs.entrySet(); } // if no inputs were provided through a previous element, obtain the // values from the request else { // check if there are parameters that don't qualify as inputs or // if inputs should be added from the pathinfo if ((mNonRequestParameterInputs != null && mNonRequestParameterInputs.size() > 0) || getPreservedInputs().size() > 0 || getPathInfoInputs().size() > 0) { HashMap<String, String[]> parameters = new HashMap<String, String[]>(getRequestParameters()); // remove the non parameter inputs from the map of request parameters if (mNonRequestParameterInputs != null && mNonRequestParameterInputs.size() > 0) { for (String non_input_param : mNonRequestParameterInputs) { parameters.remove(non_input_param); } } // add the preserved inputs if (getPreservedInputs() != null) { parameters.putAll(getPreservedInputs()); } // if pathinfo inputs were provided, add them as a last resort // without overriding the already existing inputs if (getPathInfoInputs().size() > 0) { for (Map.Entry<String, String[]> entry : getPathInfoInputs().entrySet()) { if (!parameters.containsKey(entry.getKey())) { parameters.put(entry.getKey(), entry.getValue()); } } } input_entries = parameters.entrySet(); } // just return all the request parameters else { input_entries = getRequestParameterEntries(); } } } return input_entries; } boolean isNextTrigger(ElementInfo elementInfo) { assert elementInfo != null; if (mTriggerListState != null && mTriggerListState.size() > 0 && mTriggerListState.get(0).getDeclarationName().equals(elementInfo.getDeclarationName())) { return true; } return false; } boolean isNextChildTrigger(ElementInfo elementInfo, String childName) { assert elementInfo != null; if (null == childName) { return false; } if (isNextTrigger(elementInfo) && mTriggerListState.get(0).getType() == TriggerContext.TRIGGER_CHILD && mTriggerListState.get(0).getTriggerName().equals(childName)) { return true; } return false; } boolean isNextExitTrigger(ElementInfo elementInfo, String exitName) { assert elementInfo != null; if (null == exitName) { return false; } if (isNextTrigger(elementInfo) && mTriggerListState.get(0).getType() == TriggerContext.TRIGGER_EXIT && mTriggerListState.get(0).getTriggerName().equals(exitName)) { return true; } return false; } String getNextTriggerName() { return mTriggerListState.get(0).getTriggerName(); } int getNextTriggerType() { return mTriggerListState.get(0).getType(); } String[] getNextTriggerValues() { return mTriggerListState.get(0).getTriggerValues(); } boolean hasTriggerList() { return mTriggerList != null; } void setTriggerList(List<TriggerContext> triggerList) { mTriggerList = triggerList; // make a copy of the list to be able to keep a seperate state the trace // the advancement of automatic trigger execution according // to the location and match against the trigger list mTriggerListState = new ArrayList<TriggerContext>(mTriggerList); } void addTrigger(TriggerContext triggerContext) { assert triggerContext != null; mTriggerList.add(triggerContext); } TriggerContext nextTrigger() { TriggerContext next_trigger = mTriggerListState.get(0); mTriggerListState.remove(0); return next_trigger; } String encodeTriggerList() { return TriggerListEncoder.encode(mTriggerList); } List<TriggerContext> cloneTriggerList() { return new ArrayList<TriggerContext>(mTriggerList); } RequestMethod getMethod() { return mMethod; } void setRequestParameters(Map<String, String[]> parameters) { mRequestParameters = parameters; mRequestState.setupContinuations(); clearVirtualInputs(); } Map<String, String[]> getRequestParameters() { if (null == mRequestParameters) { return mRequestState.getRequest().getParameters(); } return mRequestParameters; } Collection<String> getRequestParameterNames() { return getRequestParameters().keySet(); } boolean hasRequestParameterValue(String name) { assert name != null; assert name.length() > 0; return getRequestParameters().containsKey(name); } String getRequestParameter(String name) { assert name != null; assert name.length() > 0; String[] parameters = getRequestParameters().get(name); if (null == parameters) { return null; } return parameters[0]; } String[] getRequestParameterValues(String name) { assert name != null; assert name.length() > 0; return getRequestParameters().get(name); } Set<Map.Entry<String, String[]>> getRequestParameterEntries() { return getRequestParameters().entrySet(); } public ElementExecutionState clone() { ElementExecutionState new_elementstate = null; try { new_elementstate = (ElementExecutionState)super.clone(); } catch (CloneNotSupportedException e) { ///CLOVER:OFF // this should never happen Logger.getLogger("com.uwyn.rife.site").severe(ExceptionUtils.getExceptionStackTrace(e)); return null; ///CLOVER:ON } new_elementstate.mRequestState = null; if (mInheritanceStack != null) { new_elementstate.mInheritanceStack = new Stack<String>(); new_elementstate.mInheritanceStack.addAll(mInheritanceStack); } if (null == mRequestParameters) { new_elementstate.mRequestParameters = new HashMap<String, String[]>(mRequestState.getRequest().getParameters()); } else { new_elementstate.mRequestParameters = new HashMap<String, String[]>(mRequestParameters); } if (mTriggerInputs != null) { new_elementstate.mTriggerInputs = new HashMap<String, String[]>(mTriggerInputs); } if (mPreservedInputs != null) { new_elementstate.mPreservedInputs = new HashMap<String, String[]>(mPreservedInputs); } if (mPathInfoInputs != null) { new_elementstate.mPathInfoInputs = new HashMap<String, String[]>(mPathInfoInputs); } if (mNonRequestParameterInputs != null) { new_elementstate.mNonRequestParameterInputs = new HashSet<String>(mNonRequestParameterInputs); } if (mTriggerList != null) { new_elementstate.mTriggerList = new ArrayList<TriggerContext>(mTriggerList); } if (mTriggerListState != null) { new_elementstate.mTriggerListState = new ArrayList<TriggerContext>(mTriggerListState); } return new_elementstate; } }