001: /*
002: * Copyright 2001-2007 Geert Bevin <gbevin[remove] at uwyn dot com>
003: * Distributed under the terms of either:
004: * - the common development and distribution license (CDDL), v1.0; or
005: * - the GNU Lesser General Public License, v2.1 or later
006: * $Id: ElementExecutionState.java 3634 2007-01-08 21:42:24Z gbevin $
007: */
008: package com.uwyn.rife.engine;
009:
010: import java.util.*;
011:
012: import com.uwyn.rife.tools.ExceptionUtils;
013: import java.util.logging.Logger;
014: import java.util.regex.Matcher;
015:
016: class ElementExecutionState implements Cloneable {
017: private RequestState mRequestState = null;
018:
019: private RequestMethod mMethod = null;
020: private String mPathInfo = null;
021: private Stack<ElementInfo> mInheritanceStack = null;
022: private Map<String, String[]> mRequestParameters = null;
023: private Map<String, String[]> mTriggerInputs = null;
024: private Map<String, String[]> mPreservedInputs = null;
025: private Map<String, String[]> mPathInfoInputs = null;
026: private HashSet<String> mNonRequestParameterInputs = null;
027: private List<TriggerContext> mTriggerList = null;
028: private List<TriggerContext> mTriggerListState = null;
029:
030: ElementExecutionState(RequestState requestState) {
031: setRequestState(requestState);
032:
033: if (mRequestState.getRequest() != null) {
034: setMethod(mRequestState.getRequest().getMethod());
035: }
036: }
037:
038: void setRequestState(RequestState request) {
039: mRequestState = request;
040: }
041:
042: void setPathInfo(String pathInfo) {
043: mPathInfo = pathInfo;
044: clearVirtualInputs();
045: }
046:
047: String getPathInfo() {
048: return mPathInfo;
049: }
050:
051: void setMethod(RequestMethod method) {
052: assert method != null;
053:
054: mMethod = method;
055: }
056:
057: void setInheritanceStack(Stack<ElementInfo> inheritanceStack) {
058: mInheritanceStack = inheritanceStack;
059: }
060:
061: Stack<ElementInfo> getInheritanceStack() {
062: return mInheritanceStack;
063: }
064:
065: void setTriggerInputs(Map<String, String[]> inputs) {
066: mTriggerInputs = inputs;
067: }
068:
069: Map<String, String[]> getTriggerInputs() {
070: return mTriggerInputs;
071: }
072:
073: void setNonRequestParameterInputs(HashSet<String> set) {
074: mNonRequestParameterInputs = set;
075: }
076:
077: boolean isInheritanceTarget() {
078: if (mInheritanceStack != null && 0 == mInheritanceStack.size()) {
079: return true;
080: }
081: return false;
082: }
083:
084: boolean inInheritanceStructure() {
085: if (mInheritanceStack != null && mInheritanceStack.size() > 0) {
086: return true;
087: }
088: return false;
089: }
090:
091: private boolean isNonRequestParameterInput(String name) {
092: if (null == mNonRequestParameterInputs) {
093: return false;
094: }
095:
096: return mNonRequestParameterInputs.contains(name);
097: }
098:
099: void clearVirtualInputs() {
100: mPathInfoInputs = null;
101: mPreservedInputs = null;
102: }
103:
104: private Map<String, String[]> getPreservedInputs() {
105: if (mPreservedInputs != null) {
106: return mPreservedInputs;
107: }
108:
109: Map<String, String[]> result = null;
110:
111: // merges the global preserved inputs with the element's preserved inputs
112: ResultStates preserved = mRequestState
113: .getElementResultStatesRestored();
114: if (preserved.size() > 0) {
115: // get the global result state
116: ElementResultState global_result_state = preserved.get("");
117: if (global_result_state != null) {
118: result = global_result_state.getPreservedInputs();
119: }
120:
121: // merge the element's result state
122: ElementResultState element_result_state = preserved
123: .get(mRequestState.buildContextId());
124: if (element_result_state != null) {
125: Map<String, String[]> element_inputs_map = element_result_state
126: .getPreservedInputs();
127: if (null == result) {
128: result = element_inputs_map;
129: } else {
130: result.putAll(element_inputs_map);
131: }
132: }
133: }
134:
135: if (null == result) {
136: result = Collections.EMPTY_MAP;
137: }
138:
139: mPreservedInputs = result;
140:
141: return mPreservedInputs;
142: }
143:
144: private Map<String, String[]> getPathInfoInputs() {
145: if (mPathInfoInputs != null) {
146: return mPathInfoInputs;
147: }
148:
149: if (mRequestState.getTarget().hasPathInfoMappings()) {
150: Map<String, String[]> inputs = new HashMap<String, String[]>();
151:
152: Matcher matcher;
153: Iterator<String> input_names_it;
154: for (PathInfoMapping mapping : mRequestState.getTarget()
155: .getPathInfoMappings()) {
156: matcher = mapping.getRegexp().matcher(mPathInfo);
157: if (matcher.matches()) {
158: input_names_it = mapping.getInputs().iterator();
159: for (int i = 1; i <= mapping.getInputs().size(); i++) {
160: inputs.put(input_names_it.next(),
161: new String[] { matcher.group(i) });
162: }
163: break;
164: }
165: }
166:
167: mPathInfoInputs = inputs;
168: } else {
169: mPathInfoInputs = Collections.EMPTY_MAP;
170: }
171:
172: return mPathInfoInputs;
173: }
174:
175: /*
176: * Inputs should only come from a HTTP request in a direct access.
177: *
178: * If inputs are provided through exits, the request is not checked.
179: *
180: * If inputs are provided through inheritance, the request is not checked,
181: * unless the element is the target element.
182: * In this case the original request is restored. However, in the meantime,
183: * values might have been modified higher in parent elements through the
184: * modification of global variables.
185: * Therefore, when inputs are requested in a target element of an inheritance
186: * stack, first the provided inputs are checked and then the original request.
187: */
188: String[] getInputValues(String name) {
189: return getInputValues(name, true);
190: }
191:
192: String[] getInputValues(String name, boolean usePreservedInputs) {
193: assert name != null;
194: assert name.length() > 0;
195:
196: String[] input_values = null;
197:
198: if (isInheritanceTarget()) {
199: if (mTriggerInputs != null) {
200: input_values = mTriggerInputs.get(name);
201: }
202:
203: if (null == input_values && getPreservedInputs() != null) {
204: input_values = getPreservedInputs().get(name);
205: }
206:
207: if (null == input_values
208: && !isNonRequestParameterInput(name)) {
209: input_values = getRequestParameterValues(name);
210: }
211:
212: // if pathinfo inputs were provided, check them as a last resort
213: if (null == input_values && getPathInfoInputs().size() > 0) {
214: input_values = getPathInfoInputs().get(name);
215: }
216: } else {
217: // try to obtain the input from a previous element
218: // (arrived at the current element through an exit)
219: if (mTriggerInputs != null) {
220: input_values = mTriggerInputs.get(name);
221: }
222: // if no inputs were provided through a previous element, obtain the
223: // values from the request
224: else {
225: if (getPreservedInputs() != null) {
226: input_values = getPreservedInputs().get(name);
227: }
228:
229: if (null == input_values
230: && !isNonRequestParameterInput(name)) {
231: input_values = getRequestParameterValues(name);
232: }
233:
234: // if pathinfo inputs were provided, check them as a last resort
235: if (null == input_values
236: && getPathInfoInputs().size() > 0) {
237: input_values = getPathInfoInputs().get(name);
238: }
239: }
240: }
241:
242: return input_values;
243: }
244:
245: boolean hasInputValue(String name) {
246: return getInputValues(name) != null;
247: }
248:
249: String getInput(String name) {
250: String[] input_value = getInputValues(name);
251: if (null == input_value) {
252: return null;
253: }
254:
255: return input_value[0];
256: }
257:
258: Set<Map.Entry<String, String[]>> getInputEntries() {
259: Set<Map.Entry<String, String[]>> input_entries = null;
260:
261: if (isInheritanceTarget()) {
262: HashMap<String, String[]> inputs_merge = new HashMap<String, String[]>();
263:
264: // put all the request parameters in the map
265: inputs_merge.putAll(getRequestParameters());
266:
267: // remove all the request parameters that don't qualify as inputs
268: if (mNonRequestParameterInputs != null) {
269: for (String non_input_param : mNonRequestParameterInputs) {
270: inputs_merge.remove(non_input_param);
271: }
272: }
273:
274: // put and override the map entries with the element inputs
275: inputs_merge.putAll(mTriggerInputs);
276:
277: // add the preserved inputs
278: if (getPreservedInputs() != null) {
279: inputs_merge.putAll(getPreservedInputs());
280: }
281:
282: // if pathinfo inputs were provided, add them as a last resort
283: // without overriding the already existing inputs
284: if (getPathInfoInputs().size() > 0) {
285: for (Map.Entry<String, String[]> entry : getPathInfoInputs()
286: .entrySet()) {
287: if (!inputs_merge.containsKey(entry.getKey())) {
288: inputs_merge.put(entry.getKey(), entry
289: .getValue());
290: }
291: }
292: }
293:
294: // get the entries of the map
295: input_entries = inputs_merge.entrySet();
296: } else {
297: // try to obtain the input entries from a previous element
298: // (arrived at the current element through an exit)
299: if (mTriggerInputs != null) {
300: input_entries = mTriggerInputs.entrySet();
301: }
302: // if no inputs were provided through a previous element, obtain the
303: // values from the request
304: else {
305: // check if there are parameters that don't qualify as inputs or
306: // if inputs should be added from the pathinfo
307: if ((mNonRequestParameterInputs != null && mNonRequestParameterInputs
308: .size() > 0)
309: || getPreservedInputs().size() > 0
310: || getPathInfoInputs().size() > 0) {
311: HashMap<String, String[]> parameters = new HashMap<String, String[]>(
312: getRequestParameters());
313:
314: // remove the non parameter inputs from the map of request parameters
315: if (mNonRequestParameterInputs != null
316: && mNonRequestParameterInputs.size() > 0) {
317: for (String non_input_param : mNonRequestParameterInputs) {
318: parameters.remove(non_input_param);
319: }
320: }
321:
322: // add the preserved inputs
323: if (getPreservedInputs() != null) {
324: parameters.putAll(getPreservedInputs());
325: }
326:
327: // if pathinfo inputs were provided, add them as a last resort
328: // without overriding the already existing inputs
329: if (getPathInfoInputs().size() > 0) {
330: for (Map.Entry<String, String[]> entry : getPathInfoInputs()
331: .entrySet()) {
332: if (!parameters.containsKey(entry.getKey())) {
333: parameters.put(entry.getKey(), entry
334: .getValue());
335: }
336: }
337: }
338:
339: input_entries = parameters.entrySet();
340: }
341: // just return all the request parameters
342: else {
343: input_entries = getRequestParameterEntries();
344: }
345: }
346: }
347:
348: return input_entries;
349: }
350:
351: boolean isNextTrigger(ElementInfo elementInfo) {
352: assert elementInfo != null;
353:
354: if (mTriggerListState != null
355: && mTriggerListState.size() > 0
356: && mTriggerListState.get(0).getDeclarationName()
357: .equals(elementInfo.getDeclarationName())) {
358: return true;
359: }
360:
361: return false;
362: }
363:
364: boolean isNextChildTrigger(ElementInfo elementInfo, String childName) {
365: assert elementInfo != null;
366:
367: if (null == childName) {
368: return false;
369: }
370:
371: if (isNextTrigger(elementInfo)
372: && mTriggerListState.get(0).getType() == TriggerContext.TRIGGER_CHILD
373: && mTriggerListState.get(0).getTriggerName().equals(
374: childName)) {
375: return true;
376: }
377:
378: return false;
379: }
380:
381: boolean isNextExitTrigger(ElementInfo elementInfo, String exitName) {
382: assert elementInfo != null;
383:
384: if (null == exitName) {
385: return false;
386: }
387:
388: if (isNextTrigger(elementInfo)
389: && mTriggerListState.get(0).getType() == TriggerContext.TRIGGER_EXIT
390: && mTriggerListState.get(0).getTriggerName().equals(
391: exitName)) {
392: return true;
393: }
394:
395: return false;
396: }
397:
398: String getNextTriggerName() {
399: return mTriggerListState.get(0).getTriggerName();
400: }
401:
402: int getNextTriggerType() {
403: return mTriggerListState.get(0).getType();
404: }
405:
406: String[] getNextTriggerValues() {
407: return mTriggerListState.get(0).getTriggerValues();
408: }
409:
410: boolean hasTriggerList() {
411: return mTriggerList != null;
412: }
413:
414: void setTriggerList(List<TriggerContext> triggerList) {
415: mTriggerList = triggerList;
416: // make a copy of the list to be able to keep a seperate state the trace
417: // the advancement of automatic trigger execution according
418: // to the location and match against the trigger list
419: mTriggerListState = new ArrayList<TriggerContext>(mTriggerList);
420: }
421:
422: void addTrigger(TriggerContext triggerContext) {
423: assert triggerContext != null;
424:
425: mTriggerList.add(triggerContext);
426: }
427:
428: TriggerContext nextTrigger() {
429: TriggerContext next_trigger = mTriggerListState.get(0);
430: mTriggerListState.remove(0);
431:
432: return next_trigger;
433: }
434:
435: String encodeTriggerList() {
436: return TriggerListEncoder.encode(mTriggerList);
437: }
438:
439: List<TriggerContext> cloneTriggerList() {
440: return new ArrayList<TriggerContext>(mTriggerList);
441: }
442:
443: RequestMethod getMethod() {
444: return mMethod;
445: }
446:
447: void setRequestParameters(Map<String, String[]> parameters) {
448: mRequestParameters = parameters;
449: mRequestState.setupContinuations();
450: clearVirtualInputs();
451: }
452:
453: Map<String, String[]> getRequestParameters() {
454: if (null == mRequestParameters) {
455: return mRequestState.getRequest().getParameters();
456: }
457:
458: return mRequestParameters;
459: }
460:
461: Collection<String> getRequestParameterNames() {
462: return getRequestParameters().keySet();
463: }
464:
465: boolean hasRequestParameterValue(String name) {
466: assert name != null;
467: assert name.length() > 0;
468:
469: return getRequestParameters().containsKey(name);
470: }
471:
472: String getRequestParameter(String name) {
473: assert name != null;
474: assert name.length() > 0;
475:
476: String[] parameters = getRequestParameters().get(name);
477: if (null == parameters) {
478: return null;
479: }
480: return parameters[0];
481: }
482:
483: String[] getRequestParameterValues(String name) {
484: assert name != null;
485: assert name.length() > 0;
486:
487: return getRequestParameters().get(name);
488: }
489:
490: Set<Map.Entry<String, String[]>> getRequestParameterEntries() {
491: return getRequestParameters().entrySet();
492: }
493:
494: public ElementExecutionState clone() {
495: ElementExecutionState new_elementstate = null;
496: try {
497: new_elementstate = (ElementExecutionState) super .clone();
498: } catch (CloneNotSupportedException e) {
499: ///CLOVER:OFF
500: // this should never happen
501: Logger.getLogger("com.uwyn.rife.site").severe(
502: ExceptionUtils.getExceptionStackTrace(e));
503: return null;
504: ///CLOVER:ON
505: }
506:
507: new_elementstate.mRequestState = null;
508:
509: if (mInheritanceStack != null) {
510: new_elementstate.mInheritanceStack = new Stack<ElementInfo>();
511: new_elementstate.mInheritanceStack
512: .addAll(mInheritanceStack);
513: }
514:
515: if (null == mRequestParameters) {
516: new_elementstate.mRequestParameters = new HashMap<String, String[]>(
517: mRequestState.getRequest().getParameters());
518: } else {
519: new_elementstate.mRequestParameters = new HashMap<String, String[]>(
520: mRequestParameters);
521: }
522:
523: if (mTriggerInputs != null) {
524: new_elementstate.mTriggerInputs = new HashMap<String, String[]>(
525: mTriggerInputs);
526: }
527:
528: if (mPreservedInputs != null) {
529: new_elementstate.mPreservedInputs = new HashMap<String, String[]>(
530: mPreservedInputs);
531: }
532:
533: if (mPathInfoInputs != null) {
534: new_elementstate.mPathInfoInputs = new HashMap<String, String[]>(
535: mPathInfoInputs);
536: }
537:
538: if (mNonRequestParameterInputs != null) {
539: new_elementstate.mNonRequestParameterInputs = new HashSet<String>(
540: mNonRequestParameterInputs);
541: }
542:
543: if (mTriggerList != null) {
544: new_elementstate.mTriggerList = new ArrayList<TriggerContext>(
545: mTriggerList);
546: }
547:
548: if (mTriggerListState != null) {
549: new_elementstate.mTriggerListState = new ArrayList<TriggerContext>(
550: mTriggerListState);
551: }
552:
553: return new_elementstate;
554: }
555: }
|