ActionCode.java :  » Web-Framework » jucas » org » jucas » actionfilter » Java Open Source

Java Open Source » Web Framework » jucas 
jucas » org » jucas » actionfilter » ActionCode.java
package org.jucas.actionfilter;

import java.net.URI;
import java.net.URISyntaxException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Iterator;
import java.util.Map;
import java.util.SortedSet;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;

import javax.servlet.http.HttpServletRequest;

import org.jucas.Conventions;
import org.jucas.JucasException;

/*
 * License
 *
 *
 * Copyright (c) 2003 Essl Christian.  All rights 
 * reserved.
 * 
 * This Licence is based on the Apache Software Licence Version 1.1.
 *
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:  
 *       "This product includes software developed by Christian Essl 
 *        and others for project Jucas (http://www.jucas.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Jucas" and "Christian Essl" must    not be used to endorse or
 * promote products derived from this    software without prior written
 * permission. For written    permission, please contact essl_christian@jucas.
 * org.
 *
 * 5. Products derived from this software may not be called "Jucas"
 *    or "Christian Essl", nor may "Jucas" or "Christian Essl"
 *    appear in their name, without prior written permission
 *    of Christian Essl (essl_christian@jucas.org).
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL CHRISTIAN ESSL OR
 * OTHER CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * 
 */

/**
 * An instanceof ActionCode is used to calculate the parameter value of the 'jucas-action' parameter
 * (see {@link PeerEventInfo}). The value of this parameter contains how paramter names map to
 * IPeer names and their properties. Also there is a code calculated so that it can be ensured that
 * the value was actually calculated by this web-app.<br><br>
 * If in an html-form values of html-form-fields should be set as properties on an IPeer the method
 * {@link #getActionName(String, IPeer, String)} should be used to set the name of the html-field.<br><br>
 * If an html-form-field should call a method on an IPeer the method {@link #getMethodActionName(String, IPeer, String)}
 * should be used to get the name for the html-field.
 * <br><br>
 * After all the methods and properties have been used in the form the value of {@link #getCode()}
 * should be sent as an html-hidden-field with the name jucas-action. You can use the 
 * convinience method {@link #getAsHtmlHiddenField()}.
 * 
 * <br><br>
 * This class may only be used under an ActionFilter.
 * 
 * <br><br>
 * @see ActionCodeURL
 * @author chris
 */
final public class ActionCode
{
  public static final String NAME_PREFIX = "jucas_";
  private static byte[] appCode;
  
  private TreeMap actions = new TreeMap(); 
  
  /**
   * creates a new ActionCode. Same as new ActionCode()
   * @return ActionCode
   */
  public static ActionCode create(){
    return new ActionCode();
  }
  /**
   * Constructor for ActionCode.
   */
  public ActionCode()
  {
    super();
  }
  
  /**
   * only used by ActionFilter
   * @param appCode
   */
  static void setAppCode(byte[] appCode){
    ActionCode.appCode = appCode;  
  }
  
  static byte[] getAppCode(){
    return appCode;
  }
  
  
  /**
   * like {@link #getActionName(String,IPeer, String)} where the fieldname is null;
   * @param peer
   * @param property
   * @return String
   */
  public String getActionName(IPeer peer,String property){
    return this.getActionName(null,peer, property);  
  }
  
  /**
   * constructs an action name for the given IPeer  and the property.
   * Also addes the action to the internal List of actions.
   * @param fieldName the name of the inputField to be returned or null if it should be created by the
   * this method automaticly
   * @param peer the peer the proerty should be set on
   * @param property the proerty
   * @return String
   * @throws IllegalArgumentException if the fieldName is not null and contains an =
   * @throws NullPointerException if the peer or the property is null
   */
  public String getActionName(String fieldName, IPeer peer,String property){
    if(fieldName != null && fieldName.indexOf('=') != -1)
      throw new IllegalArgumentException("You must provide a field name which contains no ="+fieldName);
    if(peer == null || property == null)
      throw new NullPointerException("Peer or peropety arg is null");

    //construct the name
    StringBuffer stB = new StringBuffer();
    URI beanName = peer.getBeanName();
    stB.append(beanName.toString());
    if(Conventions.isPageBeanName(beanName)){
      stB.append('#');
    }else{
      stB.append('.');
    }
    
    stB.append(property);
    String name = stB.toString();
    
    //now get see if in the treemap there is already the action
    String ret = getFieldName(fieldName, name);
    return ret;
  }
  
  
  /**
   * like {@link #getMethodActionName(String, IPeer, String)} with a fieldName null.
   * @param peer
   * @param method
   * @return String
   */
  public String getMethodActionName(IPeer peer,String method){
    return this.getMethodActionName(null, peer, method);  
  }
  /**
   * constructs an html input field name wich will call the given jucasAction_XX method for the given name.
   * Also addes the action to the internal List of actions
   * @param fieldName the name of the html-input field. May be null than automaticly one is created.
   * @param peer the peer to set the 
   * @param method the jucasAction_ method (jucasAction should not be included this will be prefixed.
   * @return String the String which should be used if the for the html-field name
   */
  public String getMethodActionName(String fieldName,IPeer peer,String method){
    if(fieldName != null && fieldName.indexOf('=') != -1)
      throw new IllegalArgumentException("You must provide a field name which contains no ="+fieldName);
    if(peer == null || method == null)
      throw new NullPointerException("Peer or method arg is null");

    StringBuffer stB = new StringBuffer();
    URI beanName = peer.getBeanName();
    stB.append(beanName.toString());
    if(Conventions.isPageBeanName(beanName)){
      stB.append('#');  
    }
    
    stB.append(PeerEventInfo.JUCAS_ACTION_METHOD_MARKER);
    stB.append(method);
    
    String name = stB.toString();
    String ret = getFieldName(fieldName, name);
    return ret;
    
  }
  
  private String getFieldName(String fieldName, String name)
  {
    String ret = (String) this.actions.get(name);
    if(ret == null){
      //otherwise we construct a new name and return it.
      if(fieldName == null)
        fieldName = NAME_PREFIX+this.actions.size();
      this.actions.put(name, fieldName);
      ret = fieldName;
    }
    return ret;
  }
  
  /**
   * Returns the calculated code
   * @return String
   */
  public String getCode() {
    //the code constists of the form:
    //md5code formName=beanName formName=beanName ...
    StringBuffer stB = new StringBuffer();
    for (Iterator it = this.actions.entrySet().iterator(); it.hasNext();)
    {
      Map.Entry entry = (Map.Entry) it.next();
      String beanName = (String) entry.getKey();
      String formName = (String) entry.getValue();
      
      stB.append(' ');
      stB.append(formName);
      stB.append('=');
      stB.append(beanName);
    }
  
    //calc the code and append;
    String toCode = stB.toString();
    String code;
    code = calcCode(toCode);

    String value = code + toCode;
    return value;      
  }
  
  private  static String calcCode(String toCode)
  {
    MessageDigest md;
    try
    {
      md = MessageDigest.getInstance("MD5");
    } catch (NoSuchAlgorithmException e)
    {
      throw new IllegalStateException("No MD5 alogaritmus found");
    }
    md.update(appCode);
    md.update(toCode.getBytes());
    String code = toHex(md.digest());
    return code;
  }
  
  
  
  private static String toHex(byte[] digest){
    StringBuffer buf = new StringBuffer();
    for(int i=0;i<digest.length;i++){
      buf.append(Integer.toHexString((int)digest[i] & 0x00ff));
    }
    return buf.toString();
  }
  
  static boolean isCodeOk(String code,String params){
    
    //calc the code and compare it with the code contained
    String code2 = calcCode(params);
    if(code2 == null || ! code2.equals(code))
      return false;
    return true;
  }
  
  static boolean parseRequest(HttpServletRequest req,PeerEventInfo info) throws JucasException{
    String encoded = req.getParameter(PeerEventInfo.JUCAS_ACTION_MARKER);
    if(encoded == null)
      return false;
    
    //get the code token
    int cut = encoded.indexOf(' ');
    String code;
    String params;
    if(cut == -1){
      code = encoded;
      params = "";
    }else{
      code = encoded.substring(0,cut);
      params = encoded.substring(cut);
    }
    
    //check the code
    if(!isCodeOk(code,params))
      return false;
    
    //now parse the params
    //use for now a StringTokenizer (replace because is slow)
    params = params.trim();
    StringTokenizer sT = new StringTokenizer(params);
    while(sT.hasMoreElements()){
      String token = sT.nextToken();
      cut = token.indexOf('=');
      if(cut == -1)
        throw new IllegalArgumentException("No valid format of params no = in param:"+token);
      String name = token.substring(0,cut);
      String beanName = token.substring(cut+1);
      //now try to get the URI
      URI uri;
      try
      {
        uri = new URI(beanName);
      } catch (URISyntaxException e)
      {
        throw new IllegalArgumentException("The uri in the param:"+token+" is not valid");
      }
      //check if the URI is a BeanName
      if(!Conventions.isValidName(uri))
        throw new IllegalArgumentException("The uri is no BeanName:"+token);
      
      if(uri.getFragment() == null)
        throw new IllegalArgumentException("No legal uri a fragment must be present:"+token);
      //get the value of the parameter from the request and set it in the Map
      String[] values = req.getParameterValues(name);
      info.addParameter(uri, values);
    }
    
    
    return true;
  }
  
  /**
   * will create a hidden html field with the name jucas-action and the value the
   * from {@link #getCode()}
   * @return String
   */
  public String getAsHtmlHiddenField(){
    StringBuffer stB = new StringBuffer("<input type=\"hidden\" name=\"");
    stB.append(PeerEventInfo.JUCAS_ACTION_MARKER);
    stB.append("\" value=\"");
    stB.append(this.getCode());
    stB.append("\">");
    return stB.toString();
  }
  
  public String getMethodAsHtmlHiddenField(IPeer peer,String method,String value){
    StringBuffer stB = new StringBuffer("<input type=\"hidden\" name=\"");
    String name = this.getMethodActionName(peer, method);
    stB.append(name);
    stB.append("\" value=\"");
    stB.append(value);
    stB.append("\">");
    return stB.toString();
  }
  
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.