/* * Copyright 2001-2008 Geert Bevin <gbevin[remove] at uwyn dot com> * Licensed under the Apache License, Version 2.0 (the "License") * $Id: StateStoreQuery.java 3918 2008-04-14 17:35:35Z gbevin $ */ package com.uwyn.rife.engine; import com.uwyn.rife.engine.exceptions.EngineException; import com.uwyn.rife.tools.StringUtils; import java.util.*; import java.util.logging.Logger; public class StateStoreQuery implements StateStore { static final int MAX_URL_LENGTH = 2048; public static final String IDENTIFIER = "query"; StateStoreQuery() { } public void init(Request request) throws EngineException { } public void exportQueryUrl(CharSequenceDeferred deferred, String url, FlowState state, ElementInfo source, String type, String name) throws EngineException { if (state.isEmpty()) { deferred.setContent(url); return; } Map<String, String[]> parameters = processState(state); String result; StringBuilder query_parameters = new StringBuilder("?"); if (parameters != null && parameters.size() > 0) { // process the exit url query parameters Iterator<String> parameter_names_it = parameters.keySet().iterator(); String parameter_name = null; String[] parameter_values = null; while (parameter_names_it.hasNext()) { boolean added_seperator = false; parameter_name = parameter_names_it.next(); parameter_values = parameters.get(parameter_name); if (null == parameter_values) { continue; } if (query_parameters.length() > 1 && !added_seperator) { added_seperator = true; query_parameters.append("&"); } for (int i = 0; i < parameter_values.length; i++) { query_parameters.append(StringUtils.encodeUrlValue(parameter_name)); query_parameters.append("="); query_parameters.append(StringUtils.encodeUrlValue(parameter_values[i])); if (i+1 < parameter_values.length) { query_parameters.append("&"); } } } } if (1 == query_parameters.length()) { deferred.setContent(url); return; } result = url+query_parameters.toString(); if (result.length() <= MAX_URL_LENGTH) { deferred.setContent(deferred.encode(result)); return; } Logger.getLogger("com.uwyn.rife.engine").warning("The "+type+" '"+name+"' of element '"+source.getId()+"' generated an URL whose length of "+result.length()+" exceeds the maximum length of "+MAX_URL_LENGTH+" bytes, using session state store instead. The generated URL was '"+result+"'."); StateStoreFactory.getInstance(StateStoreSession.IDENTIFIER).exportQueryUrl(deferred, url, state, source, type, name); } public void exportFormState(CharSequenceDeferred deferred, FlowState state, FormStateType stateType) throws EngineException { if (state.isEmpty()) { deferred.setContent(""); return; } Map<String, String[]> parameters = processState(state); if (parameters != null && parameters.size() > 0) { StringBuilder form_state = new StringBuilder(); if (FormStateType.JAVASCRIPT == stateType) { StateStoreTools.appendJavascriptHeader(form_state); } String[] parameter_values = null; for (String parameter_name : parameters.keySet()) { parameter_values = parameters.get(parameter_name); if (parameter_values != null) { for (String parameter_value : parameter_values) { if (FormStateType.PARAMS == stateType) { StateStoreTools.appendHtmlHiddenParam(form_state, deferred, parameter_name, parameter_value); } else if (FormStateType.JAVASCRIPT == stateType) { StateStoreTools.appendJavascriptHiddenParam(form_state, parameter_name, parameter_value); } } } } if (FormStateType.JAVASCRIPT == stateType) { StateStoreTools.appendJavascriptFooter(form_state); } deferred.setContent(form_state.toString()); } } public void exportFormUrl(CharSequenceDeferred deferred, String url) throws EngineException { deferred.setContent(url); } public Map<String, String[]> restoreParameters(Request request) throws EngineException { // check if the state hasn't been stored in the session due to its // length being too long if (request.getParameters().containsKey(ReservedParameters.STATEID)) { return StateStoreFactory.getInstance(StateStoreSession.IDENTIFIER).restoreParameters(request); } else { // do nothing, what the request provides is exactly the state that has // been stored in http return null; } } public ElementResultState createNewResultState(String contextId) throws EngineException { return new ElementResultStateQuery(contextId); } public Class getResultStateType() throws EngineException { return ElementResultStateQuery.class; } public ResultStates restoreResultStates(Request request) throws EngineException { ResultStates result_states = new ResultStates(); extractResultStates(request.getParameters().get(ReservedParameters.CTXT), result_states); extractResultStates(request.getParameters().get(ReservedParameters.INPUTS), result_states); return result_states; } private Map<String, String[]> processState(FlowState state) { Map<String, String[]> parameters = state.getParameters(); if (null == parameters) { parameters = new LinkedHashMap<String, String[]>(); } if (state.getSubmissionContextId() != null) { StringBuilder inputs_parameter_builder = new StringBuilder(); // add the global inputs if (state.hasSubmissionGlobalInputs()) { inputs_parameter_builder.append(ParameterMapEncoder.encodeToBase64String(state.getSubmissionGlobalInputs())); } // remember this element's inputs together with the global inputs if (state.hasSubmissionElementInputs()) { if (inputs_parameter_builder.length() > 0) { inputs_parameter_builder.append('_'); } inputs_parameter_builder.append(ParameterMapEncoder.encodeToBase64String(state.getSubmissionElementInputs(), state.getSubmissionContextId())); } if (inputs_parameter_builder.length() > 0) { parameters.put(ReservedParameters.INPUTS, new String[] {inputs_parameter_builder.toString()}); } // If the parameters contain a context inputs parameter, those values should be populated dynamically // from the preserved inputs. The context id of the submission is stored in the parameter values. // This will be used to ensure that the inputs of the submission that these context inputs // belong to aren't added a second time. ResultStates states = RequestState.getActiveRequestState().getElementResultStatesObtained(); // add the preserved inputs of the other embedded elements from previous requests inputs_parameter_builder = new StringBuilder(); for (Map.Entry<String, ElementResultState> entry : states.entrySet()) { if (entry.getKey().length() > 0 && !entry.getKey().equals(state.getSubmissionContextId())) { if (inputs_parameter_builder.length() > 0) { inputs_parameter_builder.append('_'); } inputs_parameter_builder.append(((ElementResultState)entry.getValue()).getBase64EncodedState()); } } // Set the context parameters if the value is not empty. if (inputs_parameter_builder.length() > 0) { parameters.put(ReservedParameters.CTXT, new String[] {inputs_parameter_builder.toString()}); } } return parameters; } private void extractResultStates(String[] encodedState, ResultStates states) { if (encodedState != null && encodedState.length > 0 && encodedState[0] != null && encodedState[0].length() > 0) { List<String> inputs_targeted = StringUtils.split(encodedState[0], "_"); if (inputs_targeted.size() > 0) { for (String inputs : inputs_targeted) { String[] seperated = ParameterMapEncoder.seperateBase64ContextString(inputs); if (seperated != null) { ElementResultStateQuery state = new ElementResultStateQuery(seperated[0]); state.setEncodedState(seperated[1], inputs); states.put(state); } } } } } }