かとじゅんの技術日誌

技術の話をするところ

BuriをS2JDBC対応にしてみる その3

id:makotan、ありがとう!なんとかユニットテストが通るようになりました。
基本的には、S2JDBCのServiceクラスをDaoに見せるように修正した感じ。
次はサンプルアプリをS2JDBC用に書き換えてテストしてみる。最終的にはS2Daoのjarを依存関係から外して使えるようにしてしまおうっとw つまり、BuriS2Dao非依存で使えるようにしたい。

package org.escafe.buri.compiler.util.impl.rules;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.TypeVariable;
import java.util.Iterator;
import java.util.List;

import javax.persistence.Id;
import javax.persistence.Table;

import org.escafe.buri.common.util.BuriConfiguration;
import org.escafe.buri.common.util.ClassDefUtil;
import org.escafe.buri.common.util.ClassDefUtilImpl;
import org.escafe.buri.event.util.caller.DataAccessRuleEventCaller;
import org.escafe.buri.oouo.internal.structure.BuriDataFieldType;

import org.seasar.framework.beans.BeanDesc;
import org.seasar.framework.beans.PropertyDesc;
import org.seasar.framework.beans.factory.BeanDescFactory;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.log.Logger;
import org.seasar.framework.util.ClassUtil;
import org.seasar.framework.util.StringUtil;

/**
 * S2JDBC用Dao自動設定用クラス
 * 
 * @author j5ik2o
 * 
 */
public class S2JDBCToDataAccessRule extends AbstractBuriDataFieldProcRule {

	private static Logger logger = Logger
			.getLogger(S2JDBCToDataAccessRule.class);

	protected String serviceKeyName = "service";

	public final String serviceKEY = "service";

	private BuriConfiguration configuration;

	private S2Container container;

	private ClassDefUtil classDefUtil;

	private DataAccessRuleEventCaller dataAccessRuleEventCaller;

	@Override
	public boolean getRequiredRule(BuriDataFieldType src) {
		if (hasName(src, "preprocess")) {
			return false;
		}
		return true;
	}

	public boolean isRequiredNegotiate(BuriDataFieldType src) {
		if (src.getKeys().size() == 0) {
			return true;
		}
		if (!hasName(src, "select")) {
			return true;
		}
		if (!hasName(src, "insert")) {
			return true;
		}
		if (!hasName(src, "update")) {
			return true;
		}
		if (!hasName(src, "delete")) {
			return true;
		}
		if (!hasName(src, "tableName")) {
			return true;
		}
		return false;
	}

	@Override
	public boolean fstCheckProcess(BuriDataFieldType src) {
		if (!isRequiredNegotiate(src)) {
			return false;
		}
		if (src.getCache().containsKey(serviceKeyName)) {

		} else if (hasName(src, serviceKEY)) {
			src.getCache().put(serviceKeyName, getNameVal(src, serviceKEY));
		}
		dataAccessRuleEventCaller.determinedRule(this, src);
		return true;
	}

	@Override
	public boolean process(BuriDataFieldType src) {
		// if( ! src.getCache().containsKey(serviceKeyName) ) {
		// return false;
		// }
		if (src.getCache().containsKey(serviceKeyName + "_end")) {
			return false;
		}
		negotiateService(src);
		dataAccessRuleEventCaller.endNegotiateDao(this, src);
		src.getCache().put(serviceKeyName + "_end", Boolean.TRUE);
		return false;
	}

	protected void negotiateService(BuriDataFieldType src) {
		String dtoClassName = src.getId();
		String serviceName = getServiceName(src, dtoClassName);
		if (serviceName != null) {
			src.getCache().put(serviceKeyName, serviceName);
			Class serviceClass = container.getRoot().getComponentDef(
					serviceName).getComponentClass();
			pkeySetup(src);

			if (src.getKeys().size() == 1) {
				String keyName = src.getKeys().keySet().toArray()[0].toString();
				BeanDesc beanDesc = BeanDescFactory.getBeanDesc(ClassUtil
						.forName(dtoClassName));
				Class tgtClass = beanDesc.getPropertyDesc(keyName)
						.getPropertyType();
				src.getCache().put(serviceKeyName + "_KeyType", tgtClass);
				src.getCache().put(serviceKeyName + "_KeyName", keyName);
				findAndSetupAllMethod(src, beanDesc, serviceClass);
			}
		}

	}

	/**
	 * 自動設定を行います。
	 * 
	 * @param src
	 * @param beanDesc
	 * @param serviceClass
	 */
	protected void findAndSetupAllMethod(BuriDataFieldType src,
			BeanDesc beanDesc, Class<?> serviceClass) {
		Method methods[] = serviceClass.getMethods();
		for (Method method : methods) {
			String methodName = method.getName();
			selectSetup(src, method, methodName, beanDesc);
			updateSetup(src, method, methodName, beanDesc);
			deleteSetup(src, method, methodName, beanDesc);
			selectManySetup(src, method, methodName, beanDesc);
			insertSetup(src, method, methodName, beanDesc);
			tableNameSetup(src, method, methodName, beanDesc);
			selectNextValSetup(src, method, methodName, beanDesc);
		}
	}

	/**
	 * Sequence取得用メソッド実行OGNL文をセットします。
	 * 
	 * @param src
	 * @param method
	 * @param methodName
	 * @param beanDesc
	 */
	protected void selectNextValSetup(BuriDataFieldType src, Method method,
			String methodName, BeanDesc beanDesc) {
		if (isSelectNextValMethod(src, method, methodName)) {
			String serviceName = src.getCache().get(serviceKeyName).toString();
			String pkey = (String) src.getCache().get(
					serviceKeyName + "_KeyName");
			String selectNextVal = "#data." + pkey + " = " + serviceName + "."
					+ methodName + "()";
			if (!StringUtil.isEmpty(src.getInsert())) {
				String insertStr = src.getInsert();
				StringBuffer strBuff = new StringBuffer();
				strBuff.append(selectNextVal.toString());
				strBuff.append("\n");
				strBuff.append(insertStr);
				src.setInsert(strBuff.toString());
			} else {
				src.setInsert(selectNextVal.toString());
			}
		}
	}

	/**
	 * 引数のメソッドがSequence取得用か判定します。
	 * 
	 * @param src
	 * @param method
	 * @param methodName
	 * @return
	 */
	protected boolean isSelectNextValMethod(BuriDataFieldType src,
			Method method, String methodName) {
		if (methodName.startsWith("selectNextVal")) {
			if (method.getParameterTypes().length == 0) {
				return true;
			}
		}
		return false;
	}

	/**
	 * テーブル名をセットします。
	 * 
	 * @param src
	 * @param method
	 * @param methodName
	 * @param beanDesc
	 */
	protected void tableNameSetup(BuriDataFieldType src, Method method,
			String methodName, BeanDesc beanDesc) {
		if (!StringUtil.isEmpty(src.getTableName())) {
			return;
		}
		Class<?> tgt = ClassUtil.forName(src.getId());
		String tableName = classDefUtil.getClazz(tgt).getSimpleName();
		Table table = (Table) tgt.getAnnotation(Table.class);
		if (table != null) {
			tableName = table.name();
		}
		if (!StringUtil.isEmpty(tableName)) {
			src.setTableName(tableName);
		}
	}

	/**
	 * 複数データ取得用メソッド実行OGNL文をセットします。
	 * 
	 * @param src
	 * @param method
	 * @param methodName
	 * @param beanDesc
	 */
	protected void selectManySetup(BuriDataFieldType src, Method method,
			String methodName, BeanDesc beanDesc) {
		if (!StringUtil.isEmpty(src.getSelectMany())) {
			return;
		}

		if (isSelectManyMethod(src, method, methodName)) {
			String serviceName = src.getCache().get(serviceKeyName).toString();
			src.setSelectMany(serviceName + "." + methodName + "(#data)");
		}
	}

	/**
	 * 引数のメソッドが複数データ取得用か判定します。
	 * 
	 * @param src
	 * @param method
	 * @param methodName
	 * @return
	 */
	protected boolean isSelectManyMethod(BuriDataFieldType src, Method method,
			String methodName) {
		if (methodName.startsWith("get") || methodName.startsWith("select")) {
			if (method.getParameterTypes().length == 1) {
				if (method.getParameterTypes()[0].isAssignableFrom(List.class)) {
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * データ削除用メソッド実行OGNL文をセットします。
	 * 
	 * @param src
	 * @param method
	 * @param methodName
	 * @param beanDesc
	 */
	protected void deleteSetup(BuriDataFieldType src, Method method,
			String methodName, BeanDesc beanDesc) {
		if (!StringUtil.isEmpty(src.getDelete())) {
			return;
		}

		if (isDeleteMethod(src, method, methodName)) {
			String serviceName = src.getCache().get(serviceKeyName).toString();
			src.setDelete(serviceName + "." + methodName + "(#data)");
		}
	}

	/**
	 * 引数のメソッドがデータ削除用か判定します。
	 * 
	 * @param src
	 * @param method
	 * @param methodName
	 * @return
	 */
	protected boolean isDeleteMethod(BuriDataFieldType src, Method method,
			String methodName) {
		if (methodName.startsWith("del")) {
			if (method.getParameterTypes().length == 1) {
				return true;
			}
		}
		return false;
	}

	/**
	 * データ更新用メソッド実行OGNL文をセットします。
	 * 
	 * @param src
	 * @param method
	 * @param methodName
	 * @param beanDesc
	 */
	protected void updateSetup(BuriDataFieldType src, Method method,
			String methodName, BeanDesc beanDesc) {
		if (!StringUtil.isEmpty(src.getUpdate())) {
			return;
		}

		if (isUpdateMethod(src, method, methodName)) {
			String serviceName = src.getCache().get(serviceKeyName).toString();
			src.setUpdate(serviceName + "." + methodName + "(#data)");
		}
	}

	/**
	 * 引数のメソッドがデータ更新用か判定します。
	 * 
	 * @param src
	 * @param method
	 * @param methodName
	 * @return
	 */
	protected boolean isUpdateMethod(BuriDataFieldType src, Method method,
			String methodName) {
		if (methodName.startsWith("update")) {
			if (method.getParameterTypes().length == 1) {
				return true;
			}
		}
		return false;
	}

	/**
	 * データ作成用メソッド実行OGNL文をセットします。
	 * 
	 * @param src
	 * @param method
	 * @param methodName
	 * @param beanDesc
	 */
	protected void insertSetup(BuriDataFieldType src, Method method,
			String methodName, BeanDesc beanDesc) {
		if (isInsertMethod(src, method, methodName)) {
			String serviceName = src.getCache().get(serviceKeyName).toString();
			String insertOgnl = serviceName + "." + methodName + "(#data)";
			if (!StringUtil.isEmpty(src.getInsert())) {
				String insertStr = src.getInsert();
				StringBuffer strBuff = new StringBuffer();
				strBuff.append(insertStr);
				strBuff.append("\n");
				strBuff.append(insertOgnl);
				src.setInsert(strBuff.toString());
			} else {
				src.setInsert(insertOgnl);
			}
		}
	}

	/**
	 * 引数のメソッドがデータ作成用か判定します。
	 * 
	 * @param src
	 * @param method
	 * @param methodName
	 * @return
	 */
	protected boolean isInsertMethod(BuriDataFieldType src, Method method,
			String methodName) {
		if (methodName.startsWith("insert")) {
			if (method.getParameterTypes().length == 1) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 単一データ取得用メソッド実行OGNL文をセットします。
	 * 
	 * @param src
	 * @param method
	 * @param methodName
	 * @param beanDesc
	 */
	protected void selectSetup(BuriDataFieldType src, Method method,
			String methodName, BeanDesc beanDesc) {
		if (!StringUtil.isEmpty(src.getSelect())) {
			return;
		}

		if (isSelectMethod(src, method, methodName)) {
			String keyName = src.getCache().get(serviceKeyName + "_KeyName")
					.toString();
			String serviceName = src.getCache().get(serviceKeyName).toString();
			src.setSelect(serviceName + "." + methodName + "(#data." + keyName
					+ ")");
		}
	}

	/**
	 * 引数のメソッドが単一データ取得用か判定します。
	 * 
	 * @param src
	 * @param method
	 * @param methodName
	 * @return
	 */
	protected boolean isSelectMethod(BuriDataFieldType src, Method method,
			String methodName) {
		if (methodName.startsWith("get") || methodName.startsWith("select")) {
			if (method.getParameterTypes().length == 1) {
				Class tgtClass = (Class) src.getCache().get(
						serviceKeyName + "_KeyType");
				if (method.getParameterTypes()[0].equals(tgtClass)) {
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * ID存在判定用OGNL文をセットします。
	 * 
	 * @param src
	 * @param method
	 * @param methodName
	 * @param beanDesc
	 */
	protected void pkeySetup(BuriDataFieldType src) {
		if ((src.getKeys().size() > 0) || hasName(src, "pkey")) {
			return;
		}
		Class<?> entityClass = ClassUtil.forName(src.getId());
		BeanDesc bd = BeanDescFactory.getBeanDesc(entityClass);
		for (int i = 0; i < bd.getPropertyDescSize(); i++) {
			PropertyDesc pd = bd.getPropertyDesc(i);
			Field f = pd.getField();
			Id id = f.getAnnotation(Id.class);
			if (id != null) {
				String condition = createPkeyCondition(pd);
				src.getKeys().put(pd.getPropertyName(), condition);
			}
		}
	}

	/**
	 * IDアノテーションのフィールド型を判定し、ID存在判定OGNL文を返却します。
	 * 
	 * @param src
	 * @param method
	 * @param methodName
	 * @param beanDesc
	 */
	protected String createPkeyCondition(PropertyDesc pd) {
		String condition = null;
		String pkeyName = pd.getPropertyName();
		Class propType = pd.getPropertyType();
		if (propType.equals(Long.TYPE)) {
			condition = pkeyName + " != 0";
		} else if (propType.equals(Long.class)) {
			condition = pkeyName + " != null" + " && " + pkeyName + " != 0";
		} else if (propType.isAssignableFrom(Number.class)) {
			condition = pkeyName + " != 0";
		} else {
			condition = pkeyName + " != null";
		}
		return condition;
	}

	protected String getServiceName(BuriDataFieldType src, String dtoClassName) {
		String service = null;
		String shtName = createServiceName(src, dtoClassName);
		String shtName2 = shtName.substring(0, 1).toLowerCase()
				+ shtName.substring(1);
		if (container.getRoot().hasComponentDef(shtName)) {
			service = shtName;
		} else if (container.getRoot().hasComponentDef(shtName2)) {
			service = shtName2;
		} else {
			service = findserviceClass(shtName, dtoClassName);
		}
		if (service == null) {
			service = findserviceClassFromNamespace(shtName, dtoClassName);
		}
		return service;
	}

	protected String findserviceClassFromNamespace(String shtName,
			String dtoClassName) {
		String service = null;
		List serviceNamespace = configuration.getValList("Namespace");
		Iterator ite = serviceNamespace.iterator();
		while (ite.hasNext()) {
			String nameSpace = ite.next().toString();
			String componentName = nameSpace + "." + shtName;
			if (container.getRoot().hasComponentDef(componentName)) {
				return componentName;
			}
		}
		return service;
	}

	protected String findserviceClass(String shtName, String dtoClassName) {
		String service = null;
		List servicePackageName = configuration
				.getValList("servicePackageName");
		Iterator ite = servicePackageName.iterator();
		while (ite.hasNext()) {
			String pacName = ite.next().toString();
			String fullName = pacName + "." + shtName;
			service = classNameToservice(fullName);
			if (service != null) {
				break;
			}
		}
		/*
		 * if(service == null) { service =
		 * genarateserviceClass(shtName,dtoClassName); }
		 */
		return service;
	}

	/*
	 * protected String genarateserviceClass(String shtName,String dtoClassName)
	 * { Class tgtClass = ClassUtil.forName(dtoClassName); String packageName =
	 * tgtClass.getPackage().getName(); packageName =
	 * packageName.replaceAll("dto","service") + "." + shtName; packageName =
	 * classNameToservice(packageName); return packageName; }
	 */

	protected String classNameToservice(String fullName) {
		String service = null;
		if (ClassDefUtilImpl.isClassName(fullName)) {
			Class serviceClass = ClassUtil.forName(fullName);
			if (container.getRoot().hasComponentDef(serviceClass)) {
				service = container.getRoot().getComponentDef(serviceClass)
						.getComponentName();
			}
		}
		return service;
	}

	protected String createServiceName(BuriDataFieldType src,
			String dtoClassName) {
		if (hasName(src, serviceKEY)) {
			return getNameVal(src, serviceKEY);
		}
		if (dtoClassName.indexOf("$$") > -1) {
			int enhansPos = dtoClassName.indexOf("$$");
			dtoClassName = dtoClassName.substring(0, enhansPos);
		}
		Class tgtClass = ClassUtil.forName(dtoClassName);
		String shtName = ClassUtil.getShortClassName(tgtClass);
		if (shtName.length() > 3) {
			if (shtName.substring(shtName.length() - 3).equalsIgnoreCase("Dto")) {
				shtName = shtName.substring(0, shtName.length() - 3);
			}
		}
		if (shtName.length() > 6) {
			if (shtName.substring(shtName.length() - 6).equalsIgnoreCase(
					"Entity")) {
				shtName = shtName.substring(0, shtName.length() - 6);
			}
		}
		shtName = shtName + "Service";
		return shtName;
	}

	public S2Container getContainer() {
		return container;
	}

	public void setContainer(S2Container container) {
		this.container = container;
	}

	public BuriConfiguration getConfiguration() {
		return configuration;
	}

	public void setConfiguration(BuriConfiguration configuration) {
		this.configuration = configuration;
	}

	public ClassDefUtil getClassDefUtil() {
		return classDefUtil;
	}

	public void setClassDefUtil(ClassDefUtil classDefUtil) {
		this.classDefUtil = classDefUtil;
	}

	public DataAccessRuleEventCaller getDataAccessRuleEventCaller() {
		return dataAccessRuleEventCaller;
	}

	public void setDataAccessRuleEventCaller(
			DataAccessRuleEventCaller dataAccessRuleEventCaller) {
		this.dataAccessRuleEventCaller = dataAccessRuleEventCaller;
	}

}