/*
* Copyright 2004-2015 the Seasar Foundation and the Others.
*
* 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.seasar.framework.aop.intertype;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.seasar.framework.aop.InterType;
import org.seasar.framework.log.Logger;
import org.seasar.framework.util.ClassUtil;
import org.seasar.framework.util.StringUtil;
/**
* プロパティを追加するための{@link InterType}です。
*
* @author y-komori
*
*/
public class PropertyInterType extends AbstractInterType {
private static final String SETTER_PREFIX = "set";
private static final String GETTER_PREFIX = "get";
/**
* プロパティを追加しません。
*/
protected static final int NONE = 0;
/**
* getterメソッドだけを追加します。
*/
protected static final int READ = 1;
/**
* setterメソッドだけを追加します。
*/
protected static final int WRITE = 2;
/**
* getter、setterメソッドを追加します。
*/
protected static final int READWRITE = 3;
/**
* noneの値
*/
protected static final String STR_NONE = "none";
/**
* readの値
*/
protected static final String STR_READ = "read";
/**
* writeの値
*/
protected static final String STR_WRITE = "write";
/**
* readwriteの値
*/
protected static final String STR_READWRITE = "readwrite";
private static final String TIGER_ANNOTATION_HANDLER = "org.seasar.framework.aop.intertype.TigerPropertyAnnotationHandler";
private static final String BACKPORT175_ANNOTATION_HANDLER = "org.seasar.framework.aop.intertype.Backport175PropertyAnnotationHandler";
private static Logger logger = Logger.getLogger(PropertyInterType.class);
private static PropertyAnnotationHandler annotationHandler = new DefaultPropertyAnnotationHandler();
private boolean trace;
private int defaultPropertyType = READWRITE;
static {
setupAnnotationHandler();
}
/**
* 値を求めます。
*
* @param type
* タイプ
* @return 値
*/
protected static int valueOf(String type) {
int propertyType = NONE;
if (STR_READ.equals(type)) {
propertyType = READ;
} else if (STR_WRITE.equals(type)) {
propertyType = WRITE;
} else if (STR_READWRITE.equals(type)) {
propertyType = READWRITE;
}
return propertyType;
}
private static void setupAnnotationHandler() {
Class clazz = null;
try {
clazz = Class.forName(TIGER_ANNOTATION_HANDLER, true,
PropertyInterType.class.getClassLoader());
} catch (ClassNotFoundException e) {
try {
clazz = Class.forName(BACKPORT175_ANNOTATION_HANDLER, true,
PropertyInterType.class.getClassLoader());
} catch (ClassNotFoundException e2) {
return;
}
}
annotationHandler = (PropertyAnnotationHandler) ClassUtil
.newInstance(clazz);
}
/**
* トレースを出力するかどうか設定します。
*
* @param trace
*/
public void setTrace(boolean trace) {
this.trace = trace;
}
/**
* デフォルトのpropertyType(NONE, READ, WRITE, READWRITE)を設定します。
*
* @param defaultPropertyType
*/
public void setDefaultPropertyType(String defaultPropertyType) {
this.defaultPropertyType = valueOf(defaultPropertyType);
}
protected void introduce() {
if (logger.isDebugEnabled()) {
logger.debug("[PropertyInterType] Introducing... "
+ targetClass.getName());
}
int defaultValue = annotationHandler.getPropertyType(getTargetClass(),
defaultPropertyType);
List targetFields = getTargetFields(targetClass);
for (Iterator iter = targetFields.iterator(); iter.hasNext();) {
Field field = (Field) iter.next();
int property = annotationHandler.getPropertyType(field,
defaultValue);
switch (property) {
case READ:
createGetter(targetClass, field);
break;
case WRITE:
createSetter(targetClass, field);
break;
case READWRITE:
createGetter(targetClass, field);
createSetter(targetClass, field);
break;
default:
break;
}
}
}
private void createGetter(Class targetClass, Field targetField) {
String targetFieldName = targetField.getName();
String methodName = GETTER_PREFIX + createMethodName(targetFieldName);
if (hasMethod(methodName, null)) {
return;
}
if (logger.isDebugEnabled()) {
logger.debug("[PropertyInterType] Creating getter "
+ targetClass.getName() + "#" + methodName);
}
StringBuffer src = new StringBuffer(512);
src.append("{");
if (trace) {
src.append("org.seasar.framework.log.Logger logger =");
src.append("org.seasar.framework.log.Logger.getLogger($class);");
src.append("if(logger.isDebugEnabled()){");
src
.append("logger.debug(\"CALL \" + $class.getSuperclass().getName() + \"#");
src.append(methodName);
src.append("() : \" + this.");
src.append(targetFieldName);
src.append(");}");
}
src.append("return this.");
src.append(targetFieldName);
src.append(";}");
addMethod(targetField.getType(), methodName, src.toString());
}
private void createSetter(Class targetClass, Field targetField) {
String targetFieldName = targetField.getName();
String methodName = SETTER_PREFIX + createMethodName(targetFieldName);
if (hasMethod(methodName, targetField.getType())) {
return;
}
if (logger.isDebugEnabled()) {
logger.debug("[PropertyInterType] Creating setter "
+ targetClass.getName() + "#" + methodName);
}
StringBuffer src = new StringBuffer(512);
src.append("{");
if (trace) {
src.append("org.seasar.framework.log.Logger logger =");
src.append("org.seasar.framework.log.Logger.getLogger($class);");
src.append("if(logger.isDebugEnabled()){");
src
.append("logger.debug(\"CALL \" + $class.getSuperclass().getName() + \"#");
src.append(methodName);
src.append("(\" + $1 + \")\");}");
}
src.append("this.");
src.append(targetFieldName);
src.append(" = $1;}");
addMethod(methodName, new Class[] { targetField.getType() }, src
.toString());
}
private List getTargetFields(Class targetClass) {
final Map nominationFields = new LinkedHashMap();
gatherFields(targetClass, nominationFields);
final List targetFields = new ArrayList(nominationFields.size());
for (final Iterator it = nominationFields.values().iterator(); it
.hasNext();) {
final Field field = (Field) it.next();
final int modifier = field.getModifiers();
if (!Modifier.isPrivate(modifier)) {
targetFields.add(field);
}
}
return targetFields;
}
private void gatherFields(final Class targetClass, final Map fields) {
final Field[] declaredFields = targetClass.getDeclaredFields();
for (int i = 0; i < declaredFields.length; ++i) {
final Field field = declaredFields[i];
final String name = field.getName();
if (!fields.containsKey(name)) {
fields.put(name, field);
}
}
final Class superClass = targetClass.getSuperclass();
if (superClass != null && superClass != Object.class) {
gatherFields(superClass, fields);
}
}
private String createMethodName(String fieldName) {
String methodName = StringUtil.capitalize(fieldName);
if (methodName.endsWith("_")) {
methodName = methodName.substring(0, methodName.length() - 1);
}
return methodName;
}
private boolean hasMethod(String methodName, Class paramType) {
Class[] param = null;
if (paramType != null) {
param = new Class[] { paramType };
}
try {
getTargetClass().getMethod(methodName, param);
return true;
} catch (NoSuchMethodException e) {
return false;
}
}
/**
*
*/
public interface PropertyAnnotationHandler {
/**
* propertyTypeを返します。
*
* @param clazz
* @param defaultValue
* @return propertyType
*/
int getPropertyType(Class clazz, int defaultValue);
/**
* propertyTypeを返します。
*
* @param field
* @param defaultValue
* @return
*/
int getPropertyType(Field field, int defaultValue);
}
/**
* {@link PropertyInterType.PropertyAnnotationHandler}のデフォルト実装です。
*
*/
public static class DefaultPropertyAnnotationHandler implements
PropertyAnnotationHandler {
public int getPropertyType(Class clazz, int defaultValue) {
return defaultValue;
}
public int getPropertyType(Field field, int defaultValue) {
return defaultValue;
}
}
}