EJB Injection with JBoss 6 and Struts 1

Why the heck somebody would still use Struts 1? Well for a bunch of reasons… One of them could be a whole team already trained on it… another could be some company legacy systems using it.

And why would you use JBoss 6 with all brand new versions of this and another application servers? Worst: with all those application servers already certified for Java EE 7? The answer is: the customer has a whole environment based on it… and it is huge.

Ok, so let’s do it…

But you are a cool programmer and wanna use EJB 3 and get all its benefits. And being a cool programmer,of course you wanna just open your Action code and write:

@Inject
MyEJB myEJB;

Right? No easiest way to use an EJB to handle your action methods…

Wrong! Why?

  1. In a Struts Action the container is not handling the Action. The framework (Struts) is;
  2. So the Action instance were not created by the container;
  3. If the container didn’t created the Action instance it doesn’t get “involved” in the request cycle;
  4. The framework has no damn idea of what is the “@Inject” command. So it will ignore it;
  5. If the container is not involved and the framework doesn’t know what to do with it, how do you think you will get an EJB instance being injected if it is supposed to come from the container?

Well you probably already got the answer. The injection won’t happen! The “myEJB” will be null.

Please, please, please… don’t do it:

//@Inject
MyEJB myEJB = new MyEJB();

You will surely get a new instance, but it is not handled by the container. So you will need to do all the container duties (transaction management, pooling, security, concurrency, entity injection, etc) with your own hands. Not cool at all… (specially for a cool programmer…).

So what would you do? Answer in four classes!

The entity:

@Entity
@NamedQuery(name=FooEntity.FOO_FIND_ALL, query="SELECT f FROM FooEntity f ")
public class FooEntity implements Serializable {
	private static final long serialVersionUID = 1L;

	public static final String FOO_FIND_ALL = "FooEntity.findAll";

	@Id
	@Column(name="FOO_ID")
	private long fooId;

	@Column(name="FOO_NAME")
	private String fooName;

	public FooEntity() {

	}

	public long getFooId() {
		return fooId;
	}

	public void setFooId(long fooId) {
		this.fooId = fooId;
	}

	public String getFooName() {
		return fooName;
	}

	public void setFooName(String fooName) {
		this.fooName = fooName;
	}
}

The EJB:

@Stateless
@EJB(name=FooEJB.JNDI_NAME)
public class FooEJB {

	public static final String JNDI_NAME = "java:global/fooenv/ejb/foo";

	@PersistenceContext
	EntityManager em;

	public FooEJB() {
	}

	public List<FooEntity> findFoo() {
		return em.createNamedQuery(FooEntity.FOO_FIND_ALL).getResultList();
	}
}

The Service Locator:

public class ServiceLocator {

	public static <T> T getFromContainer(Class<T> clazz,String name) throws Exception {
		InitialContext ctx = new InitialContext();
		return (T) ctx.lookup(name);
	}
}

The Struts Action:

public class FooAction extends DispatchAction {

	private FooEJB fooEJB;

	public FooAction() {
		super();

    	try {
			fooEJB = ServiceLocator.getFromContainer(FooEJB.class, FooEJB.JNDI_NAME);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

    public ActionForward fooAction(ActionMapping actionMapping,
            ActionForm actionForm, HttpServletRequest request,
            HttpServletResponse response) {

    	request.setAttribute("findFoo", fooEJB.findFoo());
        return actionMapping.findForward("fooAction");

    }

}

Explaining:

  • The entity: just a regular entity. Just one note to the static property
    FOO_FIND_ALL that I use to name the named query and use it across the project;
  • The EJB: pay attention to the JNDI_NAME static property. It will used to registry the EJB in the container. See: @EJB(name=FooEJB.JNDI_NAME). And will be used to reference the same JNDI name in the Service Locator;
  • The Service Locator: a regular one. Receive an EJB type and name, do its job and return the instance;
  • The Struts Action: on each instance it requests to the container an EJB instance thru JNDI. As the container give the instance all the cycle is handled by it, including the EntityManager injection (@PersistenceContext).

So you can have all the benefits from a managed bean with just a simple locator and can use it with your legacy environment!

Even better: no XML files, no interfaces, no complication at all.

Do you have another good solution? Feel ok to tell me in the comments bellow.

Advertisements