简体   繁体   中英

how to access a @Stateless @LocalBean remotely

I'm following an EJB cookbook , from packt, with the following code:

package packt;

import javax.ejb.Stateless;
import javax.ejb.LocalBean;

//@Stateless
@LocalBean
@Stateless(mappedName="salutationBean")
public class Salutation {
    public String getFormalSalutation(String name) {
        return "Dear " + name;
    }
    public String getInformalSalutation(String name) {
        return "Hi " + name;
    }
}

How do i access this bean from a class which doesn't extend HttpServlet ? The servlet itself works fine:

package servlet;

import java.io.IOException;
import java.io.PrintWriter;
import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import packt.Salutation;

@WebServlet(urlPatterns = {"/SalutationServlet"})
public class SalutationServlet extends HttpServlet {

    @EJB
    private Salutation salutation;

    protected void processRequest(HttpServletRequest request,
            HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        try {
            out.println("<html>");
            out.println("<head>");
            out.println("<title>Servlet SalutationServlet</title>");
            out.println("</head>");
            out.println("<body>");
            out.println("<h1>"
                    + salutation.getFormalSalutation("Sherlock Holmes")
                    + "</h1>");
            out.println("</body>");
            out.println("</html>");
        } finally {
            out.flush();
            out.close();
        }
    }

    @Override
    protected void doGet(HttpServletRequest request,
            HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request,
            HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }
}

and is viewable from the designated URL:

thufir@dur:~$ 
thufir@dur:~$ lynx http://localhost:8080/SalutationApplication-war/SalutationServlet -dump
                              Dear Sherlock Holmes


thufir@dur:~$ 

The current structure:

thufir@dur:~/NetBeansProjects$ 
thufir@dur:~/NetBeansProjects$ tree SalutationApplication/
SalutationApplication/
├── build.xml
├── nbproject
│   ├── ant-deploy.xml
│   ├── build-impl.xml
│   ├── genfiles.properties
│   ├── private
│   │   └── private.properties
│   ├── project.properties
│   └── project.xml
├── SalutationApplication-ejb
│   ├── build.xml
│   ├── nbproject
│   │   ├── ant-deploy.xml
│   │   ├── build-impl.xml
│   │   ├── genfiles.properties
│   │   ├── private
│   │   │   └── private.properties
│   │   ├── project.properties
│   │   └── project.xml
│   └── src
│       ├── conf
│       │   └── MANIFEST.MF
│       └── java
│           └── packt
│               └── Salutation.java
├── SalutationApplication-war
│   ├── build.xml
│   ├── nbproject
│   │   ├── ant-deploy.xml
│   │   ├── build-impl.xml
│   │   ├── genfiles.properties
│   │   ├── private
│   │   │   └── private.properties
│   │   ├── project.properties
│   │   └── project.xml
│   ├── src
│   │   ├── conf
│   │   │   └── MANIFEST.MF
│   │   └── java
│   │       └── servlet
│   │           └── SalutationServlet.java
│   └── web
│       ├── index.html
│       └── WEB-INF
└── src
    └── conf
        └── MANIFEST.MF

20 directories, 27 files
thufir@dur:~/NetBeansProjects$ 

Right now it's fine that it's only a local bean, but ultimately I would like the Salutation.java bean to be accessible remotely. I have a passing familiarity with EJB from Head First EJB , but that's quite old.

You can create an interface and add @Remote annotation:

@Remote
public interface MyRemoteInterface {
    void myRemoteMethod();    
}

After this, you can implement this interface in your EJB:

@LocalBean
@Stateless(mappedName="salutationBean")
public class Salutation implements MyRemoteInterface {
    public String getFormalSalutation(String name) {
        return "Dear " + name;
    }

    public String getInformalSalutation(String name) {
        return "Hi " + name;
    }

    @Override
    public void myRemoteMethod(){
        // only this method will be visible in a remote interaction
    }
}

Obviously you need to inject it in the client like

@EJB
MyRemoteInterface remote;

TIP: Don't give access to remote clients of what they don't need.


EDIT: Depends on where is the client:

  • If your client is using a java component (cdi object, other EJBs, servlet, jaxrs/jaxws artifacts) use @EJB (maybe will need to add the mappedName)
  • If you client is calling outside the ejb container (ie: a standalone java application) you can use a JNDI lookup
  • If across a network, you can expose your ejb like a web service (@WebService/@Path) and consume it... well, if you like it.

(This answer relates the my comment above.)

In objects that are not managed automatically by the container, you can initialize a manual injection by obtaining a reference to the BeanManager and let the CDI container do all the work for you. This works with everything that you can also inject into managed beans, but you don't have to do the complicated JNDI lookup.

public class CDIUtils {

    public static BeanManager beanManager() {
        try {
            return (BeanManager) new InitialContext().lookup("java:comp/BeanManager");
        } catch (NamingException e) {
            throw new IllegalStateException("Unable to obtain CDI BeanManager", e);
        }
    }

    public static void makeManagedStatic(Object obj) {
        BeanManager bm = beanManager();
        makeManaged(obj, bm);
    }

    public static void makeManaged(Object obj, BeanManager beanManager) {
        Class objClass = (Class) obj.getClass();
        AnnotatedType annotatedType = beanManager.createAnnotatedType(objClass);
        InjectionTarget injectionTarget = beanManager.createInjectionTarget(annotatedType);
        CreationalContext context = beanManager.createCreationalContext(null);
        injectionTarget.inject(obj, context);
    }

}

Suppose this was your client:

public class MyClient {
    @EJB private MyEJB myEJB;
    public void run() {
        if (myEJB == null)
            CDIUtils.makeManagedStatic(this);
        myEJB.someMethod();
    }
}

You can also simply make them managed at creation, this spares the test for null :

MyClient client = new MyClient();
CDIUtils.makeManagedStatic(client);
client.run(); // etc

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM