ModelDrivenプラグイン(作りかけ)

ovalを簡単に使いたかったので、T2で簡単なModelDrivenプラグイン(作りかけ)を作ってみました。
あくまで作りかけなのでDtoのプロパティの型にはStringしか設定できません・・・。


◇使い方
1.Dtoを作成
2.Pageクラスを作成し、ModelDrivenをimplementsします。
※Actionが呼ばれた時点で、リクエストに渡ってきたmodelにデータが入ってくる。
 サンプルでは@Beforeでvalidation部分を分離しています。

以下、使い方のサンプル(t2,ovalおよび下にあるソースが必要)

Dto
hoge.dto.LoginDto

package hoge.dto;

public class LoginDto {

	@NotNull
	@NotEmpty
	@Length(min=4, max=12)
	private String loginid;
	
	@NotNull
	@NotEmpty
	@Length(min=8, max=16)
	private String password;
	
	
	public String getLoginid() {
		return loginid;
	}

	public void setLoginid(String loginid) {
		this.loginid = loginid;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}
}


○Page
hoge.page.LoginPage

package hoge.page;

@RequestScope
@Page("login")
public class LoginPage implements ModelDriven<LoginDto>{

	private LoginDto model = new LoginDto();
	
	public Navigation validateLogin(WebContext context) {
		
		Validator validator = new Validator();
		List<ConstraintViolation> violations = validator.validate(model);
		for (ConstraintViolation violation : violations) {
			System.out.println(violation.getMessage());
		}
		if(violations.size() > 0){
			// NG.
			return Forward.to("/WEB-INF/pages/login.html");
		}
		// OK.
		return PluginDefaultNavigation.INSTANCE;
	}
	
	@POST
	@ActionParam
	@Before(method = "validateLogin")
	public Navigation login(WebContext context) {
		System.out.println("====== login =======");
		return ・・・
	}

	@Override
	public LoginDto getModel() {
		return model;
	}

}

○HTML

<html>
<head></head>
<body>
<form action="/hoge/login" method="POST">
user:<input type="text" name="loginid" /><br />
pass:<input type="text" name="password" /><br />
<input type="submit" name="login" value="ログイン" />
</form>
</body>
</html>

どこにアップしていいか分からなかったので(アップする段階でもない)とりあえずソースを貼り付けておきます・・・。(よく分かっていない部分が多いので、ソースコードのツッコミ大歓迎)

org.t2framework.plugins.interceptor.ActionInterceptorPlugin.java

package org.t2framework.plugins.interceptor;

import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.Map;

import org.seasar.framework.util.MethodUtil;
import org.t2framework.commons.meta.BeanDesc;
import org.t2framework.commons.meta.BeanDescFactory;
import org.t2framework.commons.meta.Config;
import org.t2framework.commons.meta.MethodDesc;
import org.t2framework.commons.util.Logger;
import org.t2framework.commons.util.StringUtil;
import org.t2framework.plugins.interceptor.annotation.After;
import org.t2framework.plugins.interceptor.annotation.Before;
import org.t2framework.t2.action.ActionContext;
import org.t2framework.t2.plugin.AbstractPlugin;
import org.t2framework.t2.spi.Navigation;

public class ActionInterceptorPlugin extends AbstractPlugin {
	
	protected Logger log = Logger.getLogger(ActionInterceptorPlugin.class);
	
	private void setValue(Object model, String name, Object value){
		String setterName = "set" + StringUtil.capitalize(name);
		Method[] methods = model.getClass().getMethods();
		for(int i=0; i<methods.length; i++){
			if(methods[i].getName().equals(setterName)){
				try{
					// TODO 引数の型を変換する
					MethodUtil.invoke(methods[i], model, new Object[]{value});
				}catch(IllegalArgumentException e){
					log.info(methods[i].getName()+"の引数の型が一致しませんでした", value);
				}
			}
		}
	}
	
	@Override
	@SuppressWarnings("unchecked")
	public Navigation beforeActionInvoke(ActionContext actionContext,
			MethodDesc targetMethod, Object page, Object[] args) {

		if(page instanceof ModelDriven){
			ModelDriven modelDriven = (ModelDriven) page;
			
			Object model = modelDriven.getModel();
			
			if (model !=  null) {
				Map<String, Object> params = actionContext.getRequest().getAttributesAsMap();
				if(!params.isEmpty()){
					for (Iterator<Map.Entry<String, Object>> itr = params.entrySet().iterator(); itr.hasNext();) {
						Map.Entry<String, Object> entry = itr.next();
						 try {
							 setValue(model, entry.getKey(), entry.getValue());
						 } catch (RuntimeException e) {
							 e.printStackTrace();
							 log.error("", "ActionInterceptorPlugin", "Key:" + entry.getKey() + " Value:" + entry.getValue());
						 }
					 }
				}
			}
		}
		if (targetMethod.hasConfig(Before.class)) {
			Config config = targetMethod.findConfig(Before.class);
			Before before = (Before) config.getAnnotation();
			String methodName = before.method();

			BeanDesc<Object> beanDesc = BeanDescFactory.getBeanDesc(page);
			MethodDesc beforeMethod = beanDesc.getMethodDesc(methodName);

			Navigation invoke = (Navigation) beforeMethod.invoke(page, args);
			if (invoke != null) {
				return invoke;
			}
		}
		return super.beforeActionInvoke(actionContext, targetMethod, page, args);
	}

	@Override
	public Navigation afterActionInvoke(ActionContext actionContext,
			MethodDesc targetMethod, Object page, Object[] args) {

		if (targetMethod.hasConfig(After.class)) {
			Config config = targetMethod.findConfig(After.class);
			After after = (After) config.getAnnotation();
			String methodName = after.method();

			BeanDesc<Object> beanDesc = BeanDescFactory.getBeanDesc(page);
			MethodDesc beforeMethod = beanDesc.getMethodDesc(methodName);

			Navigation invoke = (Navigation) beforeMethod.invoke(page, args);
			if (invoke != null) {
				return invoke;
			}
		}
		return super.afterActionInvoke(actionContext, targetMethod, page, args);
	}

}


org.t2framework.plugins.interceptor.ModelDriven.java

package org.t2framework.plugins.interceptor;

public interface ModelDriven<T> {

	T getModel();
	
}

org.t2framework.plugins.interceptor.annotation.Before.java

package org.t2framework.plugins.interceptor.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Before {

	String method() default "before";
	
}


org.t2framework.plugins.interceptor.annotation.After.java

package org.t2framework.plugins.interceptor.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface After{

	String method() default "after";
	
}