Package org.hdiv.dataComposer

Source Code of org.hdiv.dataComposer.AbstractDataComposer

/**
* Copyright 2005-2013 hdiv.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.hdiv.dataComposer;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hdiv.config.HDIVConfig;
import org.hdiv.idGenerator.UidGenerator;
import org.hdiv.session.ISession;
import org.hdiv.state.IPage;
import org.hdiv.state.IParameter;
import org.hdiv.state.IState;
import org.hdiv.state.Page;
import org.hdiv.state.Parameter;
import org.hdiv.util.Constants;
import org.springframework.web.util.HtmlUtils;

/**
* <p>
* It processes the data contributed by the HDIV custom tags. The aim of this class is to create an object of type
* IState for each possible request (form or link) in every page processed by the HDIV custom tags. The IState object is
* used to validate client's later requests.
* </p>
* <p>
* The process of creating an IState object is as follows: Each time a link or a form processing begins, HDIV custom
* tags set the request beginning by calling beginRequest method. Once the beginning is set, an IState object is created
* and it is fill in with all the data of the request(parameter values, non editable values, parameter types) using the
* compose method. After processing all the request data of the link or form, custom tags set the end of the processing
* by calling endRequest method.
* </p>
* <p>
* Depending on the strategy defined in HDIV configuration (memory, cipher or hash), the IState object is stored in the
* user session or is sent to the client in the html code by adding an extra parameter called _HDIV_STATE_.
* </p>
* <p>
* In the memory strategy IState objects are stored in the user session (HttpSession) while in the cipher and hash
* strategies these objects are stored in the client.
* </p>
*
* @author Roberto Velasco
*/
public abstract class AbstractDataComposer implements IDataComposer {

  /**
   * Commons Logging instance.
   */
  private static Log log = LogFactory.getLog(AbstractDataComposer.class);

  /**
   * Dash character
   */
  protected static final String DASH = "-";

  /**
   * Http session wrapper
   */
  protected ISession session;

  /**
   * Unique id generator
   */
  protected UidGenerator uidGenerator;

  /**
   * Page with the possible requests or states
   */
  protected IPage page;

  /**
   * States stack to store all states of the page <code>page</code>
   */
  private Stack<IState> statesStack;

  /**
   * HDIV configuration object.
   */
  protected HDIVConfig hdivConfig;

  /**
   * DataComposer initialization with new stack to store all states of the page <code>page</code>.
   */
  public void init() {
    this.setPage(new Page());
    this.statesStack = new Stack<IState>();
  }

  /**
   * Obtains a new unique identifier for the page.
   */
  public void initPage() {
    this.page = new Page();
    int pageId = this.session.getPageId();
    this.page.setId(pageId);
  }

  /**
   * It generates a new encoded value for the parameter <code>parameter</code> and the value <code>value</code> passed
   * as parameters. The returned value guarantees the confidentiality in the cipher and memory strategies if
   * confidentiality indicator <code>confidentiality</code> is true.
   *
   * @param parameter
   *            HTTP parameter name
   * @param value
   *            value generated by server
   * @param editable
   *            parameter type: editable(textbox, password,etc.) or non editable (hidden, select, radio, ...)
   * @return Codified value to send to the client
   */
  public String compose(String parameter, String value, boolean editable) {
    return this.compose(parameter, value, editable, false);
  }

  /**
   * It generates a new encoded value for the parameter <code>parameter</code> and the value <code>value</code> passed
   * as parameters. The returned value guarantees the confidentiality in the cipher and memory strategies if
   * confidentiality indicator <code>confidentiality</code> is true.
   *
   * @param action
   *            target action
   * @param parameter
   *            HTTP parameter name
   * @param value
   *            value generated by server
   * @param editable
   *            parameter type: editable(textbox, password,etc.) or non editable (hidden, select, radio, ...)
   * @return Codified value to send to the client
   */
  public String compose(String action, String parameter, String value, boolean editable) {

    return this.compose(action, parameter, value, editable, false, Constants.ENCODING_UTF_8);
  }

  /**
   * Adds a new IParameter object, generated from the values passed as parameters, to the current state
   * <code>state</code>. If confidentiality is activated it generates a new encoded value that will be returned by the
   * server for the parameter <code>parameter</code> in the cipher and memory strategies.
   *
   * @param parameter
   *            HTTP parameter
   * @param value
   *            value generated by server
   * @param editable
   *            Parameter type: editable(textbox, password,etc.) or non editable (hidden, select, radio, ...)
   * @param isActionParam
   *            parameter added in action attribute
   * @return Codified value to send to the client
   */
  public String compose(String parameter, String value, boolean editable, boolean isActionParam) {

    return this.compose(parameter, value, editable, isActionParam, Constants.ENCODING_UTF_8);
  }

  /**
   * It generates a new encoded value for the parameter <code>parameter</code> and the value <code>value</code> passed
   * as parameters. The returned value guarantees the confidentiality in the cipher and memory strategies if
   * confidentiality indicator <code>confidentiality</code> is true.
   *
   * @param parameter
   *            HTTP parameter name
   * @param value
   *            value generated by server
   * @param editable
   *            parameter type: editable(textbox, password,etc.) or non editable (hidden, select, radio, ...)
   * @param editableName
   *            editable name (text or textarea)
   * @return Codified value to send to the client
   * @since HDIV 1.1
   */
  public String compose(String parameter, String value, boolean editable, String editableName) {

    return this.compose(parameter, value, editable, editableName, false, null, Constants.ENCODING_UTF_8);
  }

  /**
   * It generates a new encoded value for the parameter <code>parameter</code> and the value <code>value</code> passed
   * as parameters. The returned value guarantees the confidentiality in the cipher and memory strategies if
   * confidentiality indicator <code>confidentiality</code> is true.
   *
   * @param action
   *            target action
   * @param parameter
   *            parameter name
   * @param value
   *            value generated by server
   * @param editable
   *            parameter type: editable(textbox, password,etc.) or non editable (hidden, select,...)
   * @param isActionParam
   *            parameter added in action attribute
   * @param charEncoding
   *            character encoding
   * @return Codified value to send to the client
   */
  public String compose(String action, String parameter, String value, boolean editable, boolean isActionParam,
      String charEncoding) {

    // Get actual IState
    IState state = this.getStatesStack().peek();
    if (state.getAction() != null && state.getAction().trim().length() == 0) {
      state.setAction(action);
    }
    return this.compose(parameter, value, editable, isActionParam, charEncoding);
  }

  /**
   * Adds a new IParameter object, generated from the values passed as parameters, to the current state
   * <code>state</code>. If confidentiality is activated it generates a new encoded value that will be returned by the
   * server for the parameter <code>parameter</code> in the cipher and memory strategies.
   *
   * @param parameter
   *            HTTP parameter
   * @param value
   *            value generated by server
   * @param editable
   *            Parameter type: editable(textbox, password,etc.) or non editable (hidden, select, radio, ...)
   * @param isActionParam
   *            parameter added in action attribute
   * @param charEncoding
   *            character encoding
   * @return Codified value to send to the client
   */
  public String compose(String parameter, String value, boolean editable, boolean isActionParam, String charEncoding) {

    return this.compose(parameter, value, editable, null, isActionParam, null, charEncoding);
  }

  /**
   * Adds a new IParameter object, generated from the values passed as parameters, to the current state
   * <code>state</code>. If confidentiality is activated it generates a new encoded value that will be returned by the
   * server for the parameter <code>parameter</code> in the cipher and memory strategies.
   *
   * @param parameter
   *            HTTP parameter
   * @param value
   *            value generated by server
   * @param editable
   *            Parameter type: editable(textbox, password,etc.) or non editable (hidden, select, radio, ...)
   * @param editableName
   *            editable name (text or textarea)
   * @param isActionParam
   *            parameter added in action attribute
   * @param method
   *            http method, GET or POST
   * @return Codified value to send to the client
   * @since HDIV 2.1.5
   */
  public String compose(String parameter, String value, boolean editable, String editableName, boolean isActionParam,
      String method) {
    return this.compose(parameter, value, editable, editableName, isActionParam, method, Constants.ENCODING_UTF_8);
  }

  /*
   * (non-Javadoc)
   *
   * @see org.hdiv.dataComposer.IDataComposer#composeParams(java.lang.String, java.lang.String, java.lang.String)
   */
  public String composeParams(String parameters, String method, String charEncoding) {

    if (parameters == null || parameters.length() == 0) {
      return null;
    }

    String decodedParams = this.getDecodedValue(parameters, charEncoding);

    // Get actual IState
    IState state = this.getStatesStack().peek();
    state.setParams(decodedParams);

    if (this.hdivConfig.getConfidentiality()) {
      // replace real values with confidential ones
      parameters = this.applyConfidentialityToParams(parameters, method);
    }

    return parameters;
  }

  /**
   * Apply confidentiality to parameters String. Replaces real values with confidential ones.
   *
   * @param parameters
   *            parameters in query format
   * @param method
   *            HTTP method
   * @return parameters in query format with confidential values
   */
  private String applyConfidentialityToParams(String parameters, String method) {

    Map<String, Integer> pCount = new HashMap<String, Integer>();

    parameters = parameters.replaceAll("&amp;", "&");
    String newParameters = parameters;

    // Init indexes
    int beginIndex = 0;
    int endIndex = parameters.indexOf("&") > 0 ? parameters.indexOf("&") : parameters.length();
    do {
      String param = parameters.substring(beginIndex, endIndex);
      int index = param.indexOf("=");
      index = index < 0 ? param.length() : index;
      String name = param.substring(0, index);

      if (this.isConfidentialParam(name, method)) {
        // Parameter is not a start parameter
        Integer count = pCount.get(name);
        int num = (count == null) ? 0 : count + 1;
        pCount.put(name, num);

        // Replace parameter with confidential values
        newParameters = newParameters.replace(param, name + "=" + num);
      }

      // Update indexes
      beginIndex = endIndex + 1;
      endIndex = parameters.indexOf("&", endIndex + 1);
      if (endIndex < 0) {
        endIndex = parameters.length();
      }

    } while (endIndex > beginIndex);

    return newParameters;
  }

  /**
   * Adds a new IParameter object, generated from the values passed as parameters, to the current state
   * <code>state</code>. If confidentiality is activated it generates a new encoded value that will be returned by the
   * server for the parameter <code>parameter</code> in the cipher and memory strategies.
   * <p>
   * Custom method for form field.
   *
   * @param parameter
   *            HTTP parameter
   * @param value
   *            value generated by server
   * @param editable
   *            Parameter type: editable(textbox, password,etc.) or non editable (hidden, select, radio, ...)
   * @param editableName
   *            editable name (text or textarea)
   * @return Codified value to send to the client
   * @since HDIV 2.1.5
   */
  public String composeFormField(String parameter, String value, boolean editable, String editableName) {

    return this.compose(parameter, value, editable, editableName, false, "POST", Constants.ENCODING_UTF_8);
  }

  /**
   * Adds a new IParameter object, generated from the values passed as parameters, to the current state
   * <code>state</code>. If confidentiality is activated it generates a new encoded value that will be returned by the
   * server for the parameter <code>parameter</code> in the cipher and memory strategies.
   *
   * @param parameterName
   *            HTTP parameter
   * @param value
   *            value generated by server
   * @param editable
   *            Parameter type: editable(textbox, password,etc.) or non editable (hidden, select, radio, ...)
   * @param editableName
   *            editable name (text or textarea)
   * @param isActionParam
   *            parameter added in action attribute
   * @param method
   *            http method, GET or POST
   * @param charEncoding
   *            character encoding
   * @return Codified value to send to the client
   * @since HDIV 2.1.5
   */
  public String compose(String parameterName, String value, boolean editable, String editableName,
      boolean isActionParam, String method, String charEncoding) {

    if (!this.isRequestStarted()) {
      // If request not started, do nothing
      return value;
    }

    if (method == null || method.length() == 0) {
      // Default method is GET
      method = "GET";
    }

    IParameter parameter = this.composeParameter(parameterName, value, editable, editableName, isActionParam,
        charEncoding);

    if (this.isConfidentialParam(parameterName, method)) {
      return parameter.getConfidentialValue();
    } else {
      return value;
    }

  }

  /**
   * Returns true if the parameter requires confidentiality. False otherwise.
   *
   * @param parameterName
   *            the name of the parameter
   * @param method
   *            request HTTP method
   * @return boolean result
   * @since HDIV 2.1.6
   */
  protected boolean isConfidentialParam(String parameterName, String method) {

    if (!this.hdivConfig.getConfidentiality()) {
      return false;
    }

    if (this.hdivConfig.isStartParameter(parameterName)) {
      return false;
    }

    if (this.isUserDefinedNonValidationParameter(parameterName)) {
      return false;
    }

    if (this.hdivConfig.isParameterWithoutConfidentiality(parameterName)) {
      return false;
    }

    return true;
  }

  /**
   * Checks if the parameter <code>parameter</code> is defined by the user as a no required validation parameter for
   * the action <code>this.target</code>.
   *
   * @param parameter
   *            parameter name
   * @return True If it is parameter that needs no validation. False otherwise.
   * @since HDIV 2.0.6
   */
  protected boolean isUserDefinedNonValidationParameter(String parameter) {

    // Get actual IState
    IState state = this.getStatesStack().peek();
    String action = state.getAction();

    if (this.hdivConfig.isParameterWithoutValidation(action, parameter)) {

      if (log.isDebugEnabled()) {
        log.debug("parameter " + parameter + " doesn't need validation. It is user defined parameter.");
      }
      return true;
    }
    return false;
  }

  /**
   * Adds a new IParameter object, generated from the values passed as parameters, to the current state
   * <code>state</code>.
   *
   * @param parameterName
   *            HTTP parameter
   * @param value
   *            value generated by server
   * @param editable
   *            Parameter type: editable(textbox, password,etc.) or non editable (hidden, select, radio, ...)
   * @param editableDataType
   *            editable parameter name (text or textarea)
   * @param isActionParam
   *            parameter added in action attribute
   * @param charEncoding
   *            character encoding
   * @return Codified value to send to the client
   * @since HDIV 1.1
   */
  protected IParameter composeParameter(String parameterName, String value, boolean editable,
      String editableDataType, boolean isActionParam, String charEncoding) {

    // we decoded value before store it in state.
    String decodedValue = null;
    if (!editable) {
      decodedValue = this.getDecodedValue(value, charEncoding);
    }

    // Get actual IState
    IState state = this.getStatesStack().peek();

    IParameter parameter = state.getParameter(parameterName);
    if (parameter != null) {
      if (parameter.isEditable() != editable) {
        // A parameter can be created as editable but if a new non editable value is added, the parameter is
        // changed to non editable. This is required in some frameworks like Struts 2.
        parameter.setEditable(editable);
      }
      parameter.addValue(decodedValue);
    } else {
      // create a new parameter and add to the request
      parameter = createParameter(parameterName, decodedValue, editable, editableDataType, isActionParam,
          charEncoding);
      state.addParameter(parameter);
    }

    return parameter;
  }

  /**
   * Instantiates the parameter
   *
   * @param parameterName
   *            name of the parameter
   * @param decodedValue
   *            the decoded value of the parameter
   * @param editable
   *            Parameter type: editable(textbox, password,etc.) or non editable (hidden, select, radio, ...)
   * @param editableDataType
   *            editable parameter name (text or textarea)
   * @param isActionParam
   *            parameter added in action attribute
   * @param charEncoding
   *            character encoding
   * @return New IParameter object
   */
  protected IParameter createParameter(String parameterName, String decodedValue, boolean editable,
      String editableDataType, boolean isActionParam, String charEncoding) {
    return new Parameter(parameterName, decodedValue, editable, editableDataType, isActionParam);
  }

  /**
   * Creates a new parameter called <code>newParameter</code> and adds all the values of <code>oldParameter</code>
   * stored in the state to it.
   *
   * @param oldParameter
   *            name of the parameter stored in the state
   * @param newParameter
   *            name of the new parameter
   */
  public void mergeParameters(String oldParameter, String newParameter) {

    // Get actual IState
    IState state = this.getStatesStack().peek();
    IParameter storedParameter = state.getParameter(oldParameter);

    if (storedParameter.getValues().size() > 0) {

      IParameter parameter = this.composeParameter(newParameter, storedParameter.getValuePosition(0), false, "",
          false, Constants.ENCODING_UTF_8);

      String currentValue = null;
      // We check the parameters since the second position because the first
      // value has been used to create the parameter
      for (int i = 1; i < storedParameter.getValues().size(); i++) {

        currentValue = storedParameter.getValuePosition(i);
        parameter.addValue(currentValue);
      }
    }
  }

  /**
   * <p>
   * Decoded <code>value</code> using input <code>charEncoding</code>.
   * </p>
   * <p>
   * Removes Html Entity elements too. Like that:
   * </p>
   * <blockquote> &amp;#<i>Entity</i>; - <i>(Example: &amp;amp;) case sensitive</i> &amp;#<i>Decimal</i>; -
   * <i>(Example: &amp;#68;)</i><br>
   * &amp;#x<i>Hex</i>; - <i>(Example: &amp;#xE5;) case insensitive</i><br>
   * </blockquote>
   * <p>
   * Based on {@link HtmlUtils.htmlUnescape}.
   * </p>
   *
   * @param value
   *            value to decode
   * @param charEncoding
   *            character encoding
   * @return value decoded
   */
  private String getDecodedValue(String value, String charEncoding) {

    if (value == null || value.length() == 0) {
      return "";
    }

    String decodedValue = null;
    try {
      decodedValue = URLDecoder.decode(value, charEncoding);
    } catch (UnsupportedEncodingException e) {
      decodedValue = value;
    } catch (IllegalArgumentException e) {
      decodedValue = value;
    }

    // Remove escaped Html elements
    if (decodedValue.contains("&")) {
      // Can contain escaped characters
      decodedValue = HtmlUtils.htmlUnescape(decodedValue);
    }

    return (decodedValue == null) ? "" : decodedValue;
  }

  /**
   * True if beginRequest has been executed and endRequest not.
   *
   * @return boolean
   */
  public boolean isRequestStarted() {
    return this.statesStack.size() > 0;
  }

  /**
   * Adds the flow identifier to the page of type <code>IPage</code>.
   *
   * @since HDIV 2.0.3
   */
  public void addFlowId(String id) {
    this.page.setFlowId(id);
  }

  /**
   * Obtains the suffix to add to the _HDIV_STATE_ parameter in the memory and hash strategy.
   *
   * @param method
   *            HTTP method
   *
   * @return Returns suffix added to the _HDIV_STATE_ parameter.
   * @since 2.1.7
   */
  protected String getStateSuffix(String method) {

    String randomToken = this.page.getRandomToken(method);
    if (randomToken == null) {
      randomToken = this.uidGenerator.generateUid().toString();
      this.page.setRandomToken(randomToken, method);
    }
    return randomToken;
  }

  /**
   * @param session
   *            the session to set
   */
  public void setSession(ISession session) {
    this.session = session;
  }

  /**
   * @return the page
   */
  public IPage getPage() {
    return page;
  }

  /**
   * @param page
   *            the page to set
   */
  public void setPage(IPage page) {
    this.page = page;
  }

  /**
   * @param uidGenerator
   *            the uidGenerator to set
   */
  public void setUidGenerator(UidGenerator uidGenerator) {
    this.uidGenerator = uidGenerator;
  }

  /**
   * @return the statesStack
   */
  public Stack<IState> getStatesStack() {
    return statesStack;
  }

  /**
   * @param hdivConfig
   *            The HDIV configuration object to set.
   */
  public void setHdivConfig(HDIVConfig hdivConfig) {
    this.hdivConfig = hdivConfig;
  }

}
TOP

Related Classes of org.hdiv.dataComposer.AbstractDataComposer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.