Inject EJB to Struts 2 Action and Custom Validators

EJB annotation works in container managed instances such as servlet context listeners, servlets, fitlers, and even jsps. It however does not work in struts 2 actions, simply because the actions are not container managed instances and Struts 2 does not implement a hook that makes it happen. To do so, we need a “processor” that at run time checks the annotation, looks up the EJB instance and injects the EJB instance to action. The “processor” is a Struts 2 interceptor that is added to interceptor stack.

Step 1: Create the interceptor:

 public class EJBAnnotationProcessorInterceptor implements Interceptor{
 	public String intercept(ActionInvocation ai) throws Exception {
 		EJBAnnotationProcessor.process(ai.getAction());
 		return ai.invoke();
 	}
 }	

 public class EJBAnnotationProcessor {
 	public static void process(Object instance)throws Exception{
 		Field[] fields = instance.getClass().getDeclaredFields();
 		if(fields != null && fields.length > 0){
 			EJB ejb;
 			Context cxt = null;
 			String jndiName;
 			for(Field f : fields){
 				ejb = f.getAnnotation(EJB.class);
 				if(ejb != null){
 					if(cxt == null){
 						cxt = new InitialContext();
 					}
 					jndiName = getJndiName(f,ejb);
 					f.setAccessible(true);
 					f.set(instance, cxt.lookup(jndiName));
 				}
 			}
 		}
 	}
 }

Step 2: Add the interceptor to interceptor stack in struts.xml:

 <package name="base-package" extends="struts-default">
    	<interceptors>
    		<interceptor name="ejbAnnotationProcessor"
    			class="com.xyz.interceptor.EJBAnnotationProcessorInterceptor"/>
    		<interceptor-stack name="baseStack">
   			<interceptor-ref name="defaultStack"/>
    			<interceptor-ref name="ejbAnnotationProcessor"/>
    		</interceptor-stack>
    	</interceptors>
    	<default-interceptor-ref name="baseStack"/>
    </package>    <package name="package1" extends="base-package">
    	(action definitions)
    </package>

Step 3: Annotate your EJB like this:

    @Stateless(name="TestSession", mappedName="TestSession")
  	@Remote
  	@Local
  	public class TestSession implements TestInterface{
  	}

Step 4: Use your EJB in action like this:

    @EJB(mappedName="TestSession")
  	private TestInterface test;
  	public void setTest(TestInterface test){
 		this.test = test;
  	}

As for custom validator, we need to replace struts 2 AnnotationValidatorManager with our implementation that processes EJB annotations.

Step 1: The new validator manager:

 public class EJBAnnotationProcessorValidatorManager extends AnnotationActionValidatorManager{
 	public List<validator> getValidators(Class clazz,String context,String method){
 		List<validator> validators = super.getValidators(clazz,context,method);
 		for(Validator v : validators){
 			try{
 				EJBAnnotationProcessor.process(v);
 			}catch(Exception e){
 				//proces exception
 			}
 		}
 		return validators;
 	}
  }

Step 2: Define the new manager and replace struts 2 manager in struts.xml:

 <bean 	type="com.opensymphony.xwork2.validator.ActionValidatorManager"
 		name="ejbAnnotationValidatorManager"
 		class="com.xyz.validator.EJBAnnotationProcessorValidatorManager"/>
 <constant name="struts.actionValidatorManager" value="ejbAnnotationValidatorManager"/>

Step 3: Use your EJB in custom validator like this:

    @EJB(mappedName="TestSession")
  	private TestInterface test;
  	public void setTest(TestInterface test){
 		this.test = test;

  	}
原文:http://longsystemit.com/javablog/?p=40

你可能感兴趣的:(struts,ejb,2)