blob: 31aace7db76b58f8bdb6a1955cbf769dfb2acc6b [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.empire.jsf2.utils;
import java.io.Serializable;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Hashtable;
import java.util.Locale;
import org.apache.empire.commons.DateUtils;
import org.apache.empire.commons.StringUtils;
import org.apache.empire.db.DBRowSet;
import org.apache.empire.exceptions.InternalException;
import org.apache.empire.exceptions.InvalidArgumentException;
import org.apache.empire.exceptions.UnexpectedReturnValueException;
import org.apache.empire.jsf2.pages.PageDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class manages request parameters in a way that they cannot be analyzed and modified by the user
* @author doebele
*
*/
public class ParameterMap implements Serializable
{
private static final long serialVersionUID = 1L;
private static final Logger log = LoggerFactory.getLogger(ParameterMap.class);
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd hh:mm:ss", Locale.GERMAN);
static private MessageDigest md5 = null;
{
try
{
ParameterMap.md5 = MessageDigest.getInstance("MD5");
}
catch (NoSuchAlgorithmException e)
{
ParameterMap.log.error("MessageDigest NoSuchAlgorithmException.", e);
throw new InternalException(e);
}
}
private final byte[] salt;
protected Hashtable<String, String> codeMap = new Hashtable<String, String>();
protected final Hashtable<String, Hashtable<String, Object>> typeMap = new Hashtable<String, Hashtable<String, Object>>();
public ParameterMap()
{
String dateTime = dateFormat.format(DateUtils.getTimeNow());
salt = dateTime.getBytes();
}
public synchronized String encodeString(String valueAsString)
{
if (valueAsString==null)
throw new InvalidArgumentException("valueAsString", valueAsString);
// log
if (log.isTraceEnabled())
log.trace("Generating code for value {}.", valueAsString);
// generate code
md5.reset();
if (salt!=null)
md5.update(salt);
md5.update(valueAsString.getBytes());
byte s[] = ParameterMap.md5.digest();
StringBuilder hash = new StringBuilder(32);
for (int i = 0; i < s.length; i++)
{ // add the hash part
// String check = Integer.toHexString((0x000000ff & s[i]) | 0xffffff00).substring(6);;
String part = Integer.toHexString(0x000000ff & s[i]);
switch(part.length())
{
case 1: hash.append('0');
case 2: hash.append(part);
break;
default:
throw new UnexpectedReturnValueException(part, "Integer.toHexString");
// hash.append(part.substring(2));
}
}
return hash.toString();
}
public String encodeStringWithCache(String valueAsString)
{
String code = codeMap.get(valueAsString);
if (code==null)
{ // generate code
code = encodeString(valueAsString);
codeMap.put(valueAsString, code);
}
return code;
}
/**
* gets a unique name for a given rowset
* @param rowset
* @return a unique name for the given rowset
*/
protected String getRowSetTypeName(DBRowSet rowset)
{
/*
* alternatively use:
* rowset.getName();
* or
* rowset.getFullName();
*/
return rowset.getClass().getName();
}
/**
* puts an object into the parameter map
* @param typeName
* @param id
* @param value
*/
protected void putValue(String typeName, String encodedId, Object item)
{ // put in Table
if (encodedId==null)
{
throw new InvalidArgumentException("encodedId", encodedId);
}
Hashtable<String, Object> map = typeMap.get(typeName);
if (map==null)
{ map = new Hashtable<String, Object>(1);
typeMap.put(typeName, map);
}
map.put(encodedId, item);
}
/**
* encodes the objectKey and stores the item in the parameter map
* @param typeName
* @param id
* @param value
*/
protected String encodeAndStore(String typeName, String objectKey, Object item, boolean useCache)
{ // Generate the id
String encodedId = (useCache ? encodeStringWithCache(objectKey) : encodeString(objectKey));
// store
putValue(typeName, encodedId, item);
// return id
return encodedId;
}
public String put(String type, String key, boolean useCache)
{
// Generate id and put in map
return encodeAndStore(type, key, key, useCache);
}
/**
* Puts an object into the paramter map that implements the ParameterObject interface
* @param paramObject
* @return
*/
public String put(ParameterObject paramObject)
{
String objectKey;
// check param
if (paramObject==null || StringUtils.isEmpty((objectKey=paramObject.getObjectKey())))
throw new InvalidArgumentException("paramObject", paramObject);
// Generate id and put in map
String type = paramObject.getClass().getName();
return encodeAndStore(type, objectKey, paramObject, false);
}
public String put(DBRowSet rowset, Object[] key)
{
// Generate id and put in map
String rowKey = StringUtils.valueOf(key);
String type = getRowSetTypeName(rowset);
return encodeAndStore(type, rowKey, key, false);
}
/*
* do we really need this?
*
public String put(Class<? extends Object> c, Object[] key)
{
// Generate id and put in map
String ref = StringUtils.valueOf(key);
String type = c.getName();
return encodeAndStore(type, ref, key, false);
}
*/
/**
* Generates an idParam which is only valid for the given page.
* @param targetPage
* @param rowset
* @param key
* @return
*/
public String put(PageDefinition targetPage, DBRowSet rowset, Object[] key) {
// Generate id and put in map
String ref = StringUtils.valueOf(key);
String type = targetPage.getPageBeanName() + "$" + getRowSetTypeName(rowset);
return encodeAndStore(type, ref, key, false);
}
/**
* Gets an object from the parameter map for a given type and id
* @param type the object type (typically the class name)
* @param id the encoded idParam
* @return the object
*/
public Object get(String type, String id)
{
Hashtable<String, Object> map = typeMap.get(type);
return (map!=null ? map.get(id) : null);
}
public void clear(String type)
{
Hashtable<String, Object> map = typeMap.get(type);
if (map!=null)
map.clear();
}
/**
* Puts an object into the paramter map that implements the ParameterObject interface
* @param paramType
* @param id
* @return
*/
@SuppressWarnings("unchecked")
public <T extends ParameterObject> T get(Class<T> paramType, String id)
{
String type = paramType.getName();
Hashtable<String, Object> map = typeMap.get(type);
return (T)(map!=null ? map.get(id) : null);
}
public void clear(Class<? extends ParameterObject> paramType)
{
String type = paramType.getName();
clear(type);
}
/*
* do we really need this?
*
public Object[] getKey(Class<? extends Object> c, String id)
{
String type = c.getName();
Hashtable<String, Object> map = typeMap.get(type);
return (map!=null ? ((Object[])map.get(id)) : null);
}
*/
public Object[] getKey(DBRowSet rowset, String id)
{
String type = getRowSetTypeName(rowset);
Hashtable<String, Object> map = typeMap.get(type);
return (map!=null ? ((Object[])map.get(id)) : null);
}
public void clear(DBRowSet rowset)
{
String type = getRowSetTypeName(rowset);
clear(type);
}
/**
* returns an record key for a given page
* @param page
* @param rowset
* @param id
* @return
*/
public Object[] getKey(PageDefinition page, DBRowSet rowset, String id)
{
String type = page.getPageBeanName() + "$" + getRowSetTypeName(rowset);
Hashtable<String, Object> map = typeMap.get(type);
return (map!=null ? ((Object[])map.get(id)) : null);
}
}