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: StateStoreQuery.java 3634 2007-01-08 21:42:24Z gbevin $
007: */
008: package com.uwyn.rife.engine;
009:
010: import com.uwyn.rife.engine.exceptions.EngineException;
011: import com.uwyn.rife.tools.StringUtils;
012: import java.util.Iterator;
013: import java.util.LinkedHashMap;
014: import java.util.List;
015: import java.util.Map;
016: import java.util.logging.Logger;
017:
018: public class StateStoreQuery implements StateStore {
019: static final int MAX_URL_LENGTH = 2048;
020:
021: public static final String IDENTIFIER = "query";
022:
023: StateStoreQuery() {
024: }
025:
026: public void init(Request request) throws EngineException {
027: }
028:
029: public void exportQueryUrl(CharSequenceDeferred deferred,
030: String url, FlowState state, ElementInfo source,
031: String type, String name) throws EngineException {
032: if (state.isEmpty()) {
033: deferred.setContent(url);
034: return;
035: }
036:
037: Map<String, String[]> parameters = processState(state);
038:
039: String result;
040:
041: StringBuilder query_parameters = new StringBuilder("?");
042: if (parameters != null && parameters.size() > 0) {
043: // process the exit url query parameters
044: Iterator<String> parameter_names_it = parameters.keySet()
045: .iterator();
046: String parameter_name = null;
047: String[] parameter_values = null;
048:
049: while (parameter_names_it.hasNext()) {
050: boolean added_seperator = false;
051:
052: parameter_name = parameter_names_it.next();
053: parameter_values = parameters.get(parameter_name);
054: if (null == parameter_values) {
055: continue;
056: }
057:
058: if (query_parameters.length() > 1 && !added_seperator) {
059: added_seperator = true;
060: query_parameters.append("&");
061: }
062:
063: for (int i = 0; i < parameter_values.length; i++) {
064: query_parameters.append(StringUtils
065: .encodeUrlValue(parameter_name));
066: query_parameters.append("=");
067: query_parameters.append(StringUtils
068: .encodeUrlValue(parameter_values[i]));
069: if (i + 1 < parameter_values.length) {
070: query_parameters.append("&");
071: }
072: }
073: }
074: }
075:
076: if (1 == query_parameters.length()) {
077: deferred.setContent(url);
078: return;
079: }
080:
081: result = url + query_parameters.toString();
082: if (result.length() <= MAX_URL_LENGTH) {
083: deferred.setContent(deferred.encode(result));
084: return;
085: }
086:
087: Logger
088: .getLogger("com.uwyn.rife.engine")
089: .warning(
090: "The "
091: + type
092: + " '"
093: + name
094: + "' of element '"
095: + source.getId()
096: + "' generated an URL whose length of "
097: + result.length()
098: + " exceeds the maximum length of "
099: + MAX_URL_LENGTH
100: + " bytes, using session state store instead. The generated URL was '"
101: + result + "'.");
102:
103: StateStoreFactory.getInstance(StateStoreSession.IDENTIFIER)
104: .exportQueryUrl(deferred, url, state, source, type,
105: name);
106: }
107:
108: public void exportFormState(CharSequenceDeferred deferred,
109: FlowState state, FormStateType stateType)
110: throws EngineException {
111: if (state.isEmpty()) {
112: deferred.setContent("");
113: return;
114: }
115:
116: Map<String, String[]> parameters = processState(state);
117: if (parameters != null && parameters.size() > 0) {
118: StringBuilder form_state = new StringBuilder();
119: if (FormStateType.JAVASCRIPT == stateType) {
120: StateStoreTools.appendJavascriptHeader(form_state);
121: }
122:
123: String[] parameter_values = null;
124:
125: for (String parameter_name : parameters.keySet()) {
126: parameter_values = parameters.get(parameter_name);
127: if (parameter_values != null) {
128: for (String parameter_value : parameter_values) {
129: if (FormStateType.PARAMS == stateType) {
130: StateStoreTools.appendHtmlHiddenParam(
131: form_state, deferred,
132: parameter_name, parameter_value);
133: } else if (FormStateType.JAVASCRIPT == stateType) {
134: StateStoreTools
135: .appendJavascriptHiddenParam(
136: form_state, parameter_name,
137: parameter_value);
138: }
139: }
140: }
141: }
142:
143: if (FormStateType.JAVASCRIPT == stateType) {
144: StateStoreTools.appendJavascriptFooter(form_state);
145: }
146:
147: deferred.setContent(form_state.toString());
148: }
149: }
150:
151: public void exportFormUrl(CharSequenceDeferred deferred, String url)
152: throws EngineException {
153: deferred.setContent(url);
154: }
155:
156: public Map<String, String[]> restoreParameters(Request request)
157: throws EngineException {
158: // check if the state hasn't been stored in the session due to its
159: // length being too long
160: if (request.getParameters().containsKey(
161: ReservedParameters.STATEID)) {
162: return StateStoreFactory.getInstance(
163: StateStoreSession.IDENTIFIER).restoreParameters(
164: request);
165: } else {
166: // do nothing, what the request provides is exactly the state that has
167: // been stored in http
168: return null;
169: }
170: }
171:
172: public ElementResultState createNewResultState(String contextId)
173: throws EngineException {
174: return new ElementResultStateQuery(contextId);
175: }
176:
177: public Class getResultStateType() throws EngineException {
178: return ElementResultStateQuery.class;
179: }
180:
181: public ResultStates restoreResultStates(Request request)
182: throws EngineException {
183: ResultStates result_states = new ResultStates();
184: extractResultStates(request.getParameters().get(
185: ReservedParameters.CTXT), result_states);
186: extractResultStates(request.getParameters().get(
187: ReservedParameters.INPUTS), result_states);
188:
189: return result_states;
190: }
191:
192: private Map<String, String[]> processState(FlowState state) {
193: Map<String, String[]> parameters = state.getParameters();
194: if (null == parameters) {
195: parameters = new LinkedHashMap<String, String[]>();
196: }
197:
198: if (state.getSubmissionContextId() != null) {
199: StringBuilder inputs_parameter_builder = new StringBuilder();
200:
201: // add the global inputs
202: if (state.hasSubmissionGlobalInputs()) {
203: inputs_parameter_builder.append(ParameterMapEncoder
204: .encodeToBase64String(state
205: .getSubmissionGlobalInputs()));
206: }
207:
208: // remember this element's inputs together with the global inputs
209: if (state.hasSubmissionElementInputs()) {
210: if (inputs_parameter_builder.length() > 0) {
211: inputs_parameter_builder.append('_');
212: }
213: inputs_parameter_builder.append(ParameterMapEncoder
214: .encodeToBase64String(state
215: .getSubmissionElementInputs(), state
216: .getSubmissionContextId()));
217: }
218:
219: if (inputs_parameter_builder.length() > 0) {
220: parameters.put(ReservedParameters.INPUTS,
221: new String[] { inputs_parameter_builder
222: .toString() });
223: }
224:
225: // If the parameters contain a context inputs parameter, those values should be populated dynamically
226: // from the preserved inputs. The context id of the submission is stored in the parameter values.
227: // This will be used to ensure that the inputs of the submission that these context inputs
228: // belong to aren't added a second time.
229: ResultStates states = RequestState.getActiveRequestState()
230: .getElementResultStatesObtained();
231:
232: // add the preserved inputs of the other embedded elements from previous requests
233: inputs_parameter_builder = new StringBuilder();
234: for (Map.Entry<String, ElementResultState> entry : states
235: .entrySet()) {
236: if (entry.getKey().length() > 0
237: && !entry.getKey().equals(
238: state.getSubmissionContextId())) {
239: if (inputs_parameter_builder.length() > 0) {
240: inputs_parameter_builder.append('_');
241: }
242: inputs_parameter_builder
243: .append(((ElementResultStateQuery) entry
244: .getValue())
245: .getBase64EncodedState());
246: }
247: }
248:
249: // Set the context parameters if the value is not empty.
250: if (inputs_parameter_builder.length() > 0) {
251: parameters.put(ReservedParameters.CTXT,
252: new String[] { inputs_parameter_builder
253: .toString() });
254: }
255: }
256:
257: return parameters;
258: }
259:
260: private void extractResultStates(String[] encodedState,
261: ResultStates states) {
262: if (encodedState != null && encodedState.length > 0
263: && encodedState[0] != null
264: && encodedState[0].length() > 0) {
265: List<String> inputs_targeted = StringUtils.split(
266: encodedState[0], "_");
267: if (inputs_targeted.size() > 0) {
268: for (String inputs : inputs_targeted) {
269: String[] seperated = ParameterMapEncoder
270: .seperateBase64ContextString(inputs);
271: if (seperated != null) {
272: ElementResultStateQuery state = new ElementResultStateQuery(
273: seperated[0]);
274: state.setEncodedState(seperated[1], inputs);
275: states.put(state);
276: }
277: }
278: }
279: }
280: }
281: }
|