I am looking since a long time but actually have not found the correct answer for my case.
General I want to call a remote EJB without knowing all the methodes of it. As far I know, I need to use reflection to accomplish it.
The thing is should I use an interface on client side or not? Normally I use an interface for EJB calls, but I guess I need to use bytecode manipulation to create an dynamic interface at runtime???
Finally the idea is to deploy new applications to the jboss server at runtime (hotdeploy) and call the EJB from the new deployed application via the admin server (main application from the EJB). So I can add/delete/update logic/EJBs during runtime.
But the remote EJB is not every time the same (depends on the task it should execute). So I need to create an interface or class dynamically for each new deployed application/ejb I want to call. Client/admin just know the JNDI name.
Let's assume this is my interface and ejb code from a hotdeployed application. Please consider this is only one EJB out of n.
Remote EJB Interface:
import javax.ejb.Remote;
@Remote
public interface EJBInterface {
public void www();
public void store();
}
Remote EJB:
import javax.ejb.Stateless;
import com.xx.yy.EJBInterface;
@Stateless
public class EJBStuff implements EJBInterface{
@Override
public void www() {
//Do some stuff
}
@Override
public void store() {
//Do some stuff
}
}
On client/admin side I would like to call the EJB. Should I use an interface or direct a class for the implementation??? Further I assume I need to add a common EJB to each hotdeploy app, which provides me the information from the EJB I want to call so I can create an class or interface at client/admin side.
So does someone has an adivse if I should create an interface on client/admin side or a class and call the EJB without interface view??? To I need another class with provides me the info from the remote EJB???
Thanks in advise.
The solution for your problem is the "Command Design Pattern". My example is a web client to avoid the inconviniences caused by JNDI lookup (it was not the part of the question anyway)
The EJB module codes (Command, CommandType, CommandMgr, HelloBean)
The Command class is for call parameterized methods of SLSBs in an abstract way:
package x;
import java.util.HashMap;
import java.util.Map;
public class Command
{
private int type;
private final Map<String,Object> params = new HashMap<>();
public Command( int type_ ) { type = type_; }
public int getType() { return type; }
public Map<String,Object> getParams() { return params; }
public Object getParamByKey( String key_ ) { return params.get( key_ ); }
}
The available command types described by CommandType enum:
public enum CommandType { UNKNOWN, HELLO }
CommandMgr is a remote business interface to receive Command messages:
package x;
import javax.ejb.Remote;
@Remote
public interface CommandMgr
{
public Object send( Command command_ );
}
CommandMgrImpl class implements the business interface:
package x;
import java.security.InvalidParameterException;
import javax.ejb.Stateless;
import javax.inject.Inject;
@Stateless( name = "commandMgr" )
public class CommandMgrImp implements CommandMgr
{
@Inject
private HelloBean helloBean;
@Override
public Object send( Command command_ )
{
if ( command_ != null )
switch ( command_.getType() )
{
case 1:
return helloBean.sayHello( (String) command_.getParamByKey( "name" ) );
default:
return null;
}
else
throw new InvalidParameterException( "CommandMgrImp.send() : command_=null");
}
}
HelloBean is one of session beans to access via the remote interface indirectly:
package x;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Named;
@Named
@ApplicationScoped
public class HelloBean
{
public String sayHello( String name_ )
{
return "Hello " + name_ + "!";
}
}
The web client code is a common JSF web module (a page, and an EJB injected backing bean):
The hellopage.xhtml:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<title>Facelet Title</title>
</h:head>
<h:body>
<h:form>
<h:panelGrid columns="3">
Enter your name:<h:inputText id="name" value="#{commandClient.name}"/>
<h:commandButton value="Submit">
<f:ajax listener="#{commandClient.updateMessage}" execute="@form" render="msg"/>
</h:commandButton>
</h:panelGrid>
<h:messages id="msg"/>
</h:form>
</h:body>
</html>
The CommandClient is a view scoped managed bean:
package x;
import java.io.Serializable;
import javax.ejb.EJB;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.AjaxBehaviorEvent;
import javax.faces.view.ViewScoped;
import javax.inject.Named;
@Named
@ViewScoped
public class CommandClient implements Serializable
{
private String name;
@EJB
private CommandMgr commandMgr;
public String getName()
{
return name;
}
public void setName( String name_ )
{
name = name_;
}
public void updateMessage( AjaxBehaviorEvent event_ )
{
Command cmd = createHelloCommand();
FacesMessage msg = new FacesMessage( (String) commandMgr.send( cmd ) );
FacesContext.getCurrentInstance().addMessage( "name", msg );
}
protected Command createHelloCommand()
{
Command cmd = new Command( CommandType.HELLO.ordinal() );
cmd.getParams().put( "name", name );
return cmd;
}
}