blob: d1bafc78e2bddfb579255e90f4f3f2074e91c759 [file] [log] [blame]
// Copyright 2004 The Apache Software Foundation
//
// 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.apache.tapestry.enhance.javassist;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
import javassist.CannotCompileException;
import javassist.CtClass;
import javassist.CtMethod;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.tapestry.Tapestry;
import org.apache.tapestry.enhance.CodeGenerationException;
import org.apache.tapestry.enhance.IEnhancedClass;
import org.apache.tapestry.enhance.IEnhancer;
/**
* Creates a synthetic property for a
* {@link org.apache.tapestry.spec.Direction#AUTO}
* parameter.
*
* @author Mindbridge
* @version $Id$
* @since 3.0
*
**/
public class CreateAutoParameterEnhancer implements IEnhancer
{
private static final Log LOG = LogFactory.getLog(CreateAutoParameterEnhancer.class);
/**
* The code template for the parameter accessor method.
* <p>
* Legend: <br>
* {0} = readBindingMethodName <br>
* {1} = binding value accessor <br>
* {2} = cast (if needed) <br>
*/
protected static final String PARAMETER_ACCESSOR_TEMPLATE =
""
+ "'{'"
+ " org.apache.tapestry.IBinding binding = {0}();"
+ " return {2} binding.{1}(); "
+ "'}'";
/**
* The code template for the parameter mutator method.
* <p>
* Legend: <br>
* {0} = readBindingMethodName <br>
* {1} = binding value mutator <br>
* {2} = value cast
*/
protected static final String PARAMETER_MUTATOR_TEMPLATE =
""
+ "'{'"
+ " org.apache.tapestry.IBinding binding = {0}();"
+ " binding.{1}({2} $1); "
+ "'}'";
/**
* The list of types that have accessors and mutators
* other than getObject()/setObject.
* The key in the Map is the type, the value is the property name in IBinding
*/
private static final Map SPECIAL_BINDING_TYPES = new HashMap();
static {
SPECIAL_BINDING_TYPES.put("boolean", "boolean");
SPECIAL_BINDING_TYPES.put("int", "int");
SPECIAL_BINDING_TYPES.put("double", "double");
SPECIAL_BINDING_TYPES.put("java.lang.String", "string");
}
private static final Map VALUE_CAST_TYPES = new HashMap();
static {
VALUE_CAST_TYPES.put("byte", "($w)");
VALUE_CAST_TYPES.put("long", "($w)");
VALUE_CAST_TYPES.put("short", "($w)");
VALUE_CAST_TYPES.put("char", "($w)");
VALUE_CAST_TYPES.put("float", "($w)");
}
private EnhancedClass _enhancedClass;
private String _propertyName;
private String _parameterName;
private CtClass _type;
private String _readMethodName;
public CreateAutoParameterEnhancer(
EnhancedClass enhancedClass,
String propertyName,
String parameterName,
CtClass type,
String readMethodName)
{
_enhancedClass = enhancedClass;
_propertyName = propertyName;
_parameterName = parameterName;
_type = type;
_readMethodName = readMethodName;
}
public void performEnhancement(IEnhancedClass enhancedClass)
{
if (LOG.isDebugEnabled())
LOG.debug("Creating auto property: " + _propertyName);
EnhancedClass jaEnhancedClass = (EnhancedClass) enhancedClass;
ClassFabricator cf = jaEnhancedClass.getClassFabricator();
String readBindingMethodName =
cf.buildMethodName("get", _parameterName + Tapestry.PARAMETER_PROPERTY_NAME_SUFFIX);
createReadMethod(cf, readBindingMethodName);
createWriteMethod(cf, readBindingMethodName);
}
private String getSpecialBindingType()
{
String typeName = _type.getName();
return (String) SPECIAL_BINDING_TYPES.get(typeName);
}
private String getValueCastType()
{
String typeName = _type.getName();
return (String) VALUE_CAST_TYPES.get(typeName);
}
private void createReadMethod(ClassFabricator cf, String readBindingMethodName)
{
String castToType;
String bindingValueAccessor;
String specialBindingType = getSpecialBindingType();
if (specialBindingType != null)
{
castToType = "";
bindingValueAccessor = cf.buildMethodName("get", specialBindingType);
}
else
{
castToType = "($r)";
bindingValueAccessor = "getObject";
}
String readMethodBody =
MessageFormat.format(
PARAMETER_ACCESSOR_TEMPLATE,
new Object[] { readBindingMethodName, bindingValueAccessor, castToType });
try
{
CtMethod method = cf.createAccessor(_type, _propertyName, _readMethodName);
method.setBody(readMethodBody);
cf.addMethod(method);
}
catch (CannotCompileException e)
{
throw new CodeGenerationException(e);
}
}
private void createWriteMethod(ClassFabricator cf, String readBindingMethodName)
{
String bindingValueAccessor;
String valueCast = "";
String specialBindingType = getSpecialBindingType();
if (specialBindingType != null)
{
bindingValueAccessor = cf.buildMethodName("set", specialBindingType);
}
else
{
bindingValueAccessor = "setObject";
String castForType = getValueCastType();
if (castForType != null)
valueCast = castForType;
}
String writeMethodBody =
MessageFormat.format(
PARAMETER_MUTATOR_TEMPLATE,
new Object[] { readBindingMethodName, bindingValueAccessor, valueCast });
try
{
CtMethod method = cf.createMutator(_type, _propertyName);
method.setBody(writeMethodBody);
cf.addMethod(method);
}
catch (CannotCompileException e)
{
throw new CodeGenerationException(e);
}
}
}