1

I am having trouble using remote EJB objects. JNDI look-up succeeds but casting to an object and later usage fails. The EJB interface and implementation are as follows:

UserViewBeanRemote.java

package books.pointejb;

import java.util.List;

import javax.ejb.Remote;

import books.pointejb.User;
import books.pointejb.Book;

@Remote
public interface UserViewBeanRemote {
    public boolean register(User user);
    // A user can delete his/her account, note that two users with the same username cannot exist
    public void delete(User user);
    public boolean login(User user);
    public boolean logout(User user);
    // Search only by book titles
    public List<Book> search(String title);
}

UserViewBean.java

package books.pointejb;


import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.ejb.Stateful;
import javax.management.Query;
import javax.persistence.EntityManager;  
import javax.persistence.PersistenceContext;

// import javax.ejb.Remote;
import books.pointejb.User;
import books.pointejb.Book;

/**
 * Session Bean implementation class UserView
 */
@Stateful
// @Remote(UserViewBeanRemote.class)
public class UserViewBean implements UserViewBeanRemote {

    @PersistenceContext  
     private EntityManager entityManager; 
    /**
     * Default constructor. 
     */
    public UserViewBean() {
        // TODO Auto-generated constructor stub
    }

    public static <T> List<T> castList(Class<? extends T> clazz, Collection<?> c) {
        List<T> r = new ArrayList<T>(c.size());
        for(Object o: c)
          r.add(clazz.cast(o));
        return r;
    }

    @Override
    public boolean register(User user) {
        // We have servlets that validate these fields, so we don't validate anything here
        // We check to see whether there is already a user with the same user name or not
        Query query = (Query) entityManager.createQuery("SELECT u FROM users u WHERE u.username=:userName");
        ((javax.persistence.Query) query).setParameter("userName", user.getUsername());
        // We check each returned value. If we find anything than we do not add the user
        List<User> users = castList(User.class, ((javax.persistence.Query) query).getResultList());
        if(users.isEmpty()) {
            // The user is not present. Add this user
            entityManager.persist(user);
            // return "Welcome to BooksPoint " + user.getUsername() + "!";
            return true;
        } else {
            // return "Cannot create " + user.getUsername() + ". A user with this name already exists";
            return false;
        }

    }

    @Override
    public void delete(User user) {
        // The account automatically exists since the user is already logged in
        Query query = (Query) entityManager.createQuery("DELETE FROM users u WHERE u.username=:userName");
        ((javax.persistence.Query) query).setParameter("userName", user.getUsername());
        // return "Your account " + user.getUsername() + " has been removed successfully!";
    }

    @Override
    public boolean login(User user) {
        // Check if we have a valid user/pass pair
        Query query = (Query) entityManager.createQuery("SELECT u FROM users u WHERE u.username=:userName AND u.password=:password");
        ((javax.persistence.Query) query).setParameter("userName", user.getUsername());
        ((javax.persistence.Query) query).setParameter("password", user.getPassword());
        List<User> users = castList(User.class, ((javax.persistence.Query) query).getResultList());
        if(!users.isEmpty()) {
            // return "Welcome " + user.getUsername() + "!";
            return true;
        } else {
            // return "Username or password are not valid";
            return false;
        }
    }

    @Override
    public boolean logout(User user) {
        // This can be done in the jsp/servlet. Simply erase the session variables associated with the current user
        return false;
    }

    @Override
    public List<Book> search(String title) {
        // Check all entries for names similar to title
        Query query = (Query) entityManager.createQuery("SELECT * FROM books WHERE title LIKE '%:title%'");
        ((javax.persistence.Query) query).setParameter("title", title);
        List<Book> books = castList(Book.class, ((javax.persistence.Query) query).getResultList());
        // Return the books now leave the rest to the jsp
        return books;
    }
}

Uncommenting @Remote(UserViewBeanRemote.class) doesn't change this behavior. The lookup is done in the following file:

Lookup.java

package books.point;

import javax.naming.Context;
import javax.naming.NamingException;

import books.point.clientutility.ClientUtility;
import books.pointejb.CartBean;
import books.pointejb.CartBeanRemote;
import books.pointejb.UserViewBean;
import books.pointejb.UserViewBeanRemote;

public class Lookup {
    private static final String MODULE_NAME = "BooksPointEJB";

    public static UserViewBean doLookupUser() {
        Context context = null;
        UserViewBean bean = null;
        try {
            // 1. Obtaining Context
            context = ClientUtility.getInitialContext();
            // 2. Generate JNDI Lookup name
            String lookupName = getLookupNameUser();
            // 3. Lookup and cast
            bean = (UserViewBean) context.lookup(lookupName); // <== Exception is thrown here

        } catch (NamingException e) {
            e.printStackTrace();
        }
        return bean;
    }

    public static String getLookupNameUser() {
        /*
         * The app name is the EAR name of the deployed EJB without .ear suffix.
         * Since we haven't deployed the application as a .ear, the app name for
         * us will be an empty string
         */
        String appName = "";

        /*
         * The module name is the JAR name of the deployed EJB without the .jar
         * suffix.
         */
        String moduleName = MODULE_NAME;

        /*
         * AS7 allows each deployment to have an (optional) distinct name. This
         * can be an empty string if distinct name is not specified.
         */
        String distinctName = "";

        // The EJB bean implementation class name
        String beanName = UserViewBean.class.getSimpleName();

        // Fully qualified remote interface name
        final String interfaceName = UserViewBeanRemote.class.getName();

        // Create a look up string name
        // Be very careful about the stateful flag at the end
        String name = "ejb:" + appName + "/" + moduleName + "/" + distinctName
                + "/" + beanName + "!" + interfaceName + "?stateful";

// User looked up name: ejb:/BooksPointEJB//UserViewBean!books.pointejb.UserViewBeanRemote?stateful System.out.println("User Lookup name is: " + name); return name; }

    ...
}

The EJB deployment log is:

12:10:22,897 INFO  [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] (MSC service thread 1-5) JNDI bindings for session bean named UserViewBean in deployment unit deployment "BooksPoint.war" are as follows:

    java:global/BooksPoint/UserViewBean!books.pointejb.UserViewBeanRemote
    java:app/BooksPoint/UserViewBean!books.pointejb.UserViewBeanRemote
    java:module/UserViewBean!books.pointejb.UserViewBeanRemote
    java:jboss/exported/BooksPoint/UserViewBean!books.pointejb.UserViewBeanRemote
    java:global/BooksPoint/UserViewBean
    java:app/BooksPoint/UserViewBean
    java:module/UserViewBean

I am using jboss-as-7.1.1.Final. Why is this exception thrown?

12:10:52,973 INFO  [org.jboss.ejb.client] (http-localhost-127.0.0.1-8080-1) JBoss EJB Client version 1.0.5.Final
12:10:53,043 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/BooksPoint].[books.point.Register]] (http-localhost-127.0.0.1-8080-1) Servlet.service() for servlet books.point.Register threw exception: java.lang.ClassCastException: com.sun.proxy.$Proxy22 cannot be cast to books.pointejb.UserViewBean
    at books.point.Lookup.doLookupUser(Lookup.java:24) [classes:]
    at books.point.Register.doPost(Register.java:263) [classes:]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:754) [jboss-servlet-api_3.0_spec-1.0.0.Final.jar:1.0.0.Final]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:847) [jboss-servlet-api_3.0_spec-1.0.0.Final.jar:1.0.0.Final]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161) [jbossweb-7.0.13.Final.jar:]
    at org.jboss.as.jpa.interceptor.WebNonTxEmCloserValve.invoke(WebNonTxEmCloserValve.java:50) [jboss-as-jpa-7.1.1.Final.jar:7.1.1.Final]
    at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:153) [jboss-as-web-7.1.1.Final.jar:7.1.1.Final]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368) [jbossweb-7.0.13.Final.jar:]
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877) [jbossweb-7.0.13.Final.jar:]
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:671) [jbossweb-7.0.13.Final.jar:]
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930) [jbossweb-7.0.13.Final.jar:]
    at java.lang.Thread.run(Unknown Source) [rt.jar:1.7.0_45]

1 Answer 1

5

When you do a JNDI lookup, you lookup the remote Interface.

so changing your cast to

bean = (UserViewBeanRemote) context.lookup(lookupName);

should do the trick.

Sign up to request clarification or add additional context in comments.

1 Comment

That was the problem indeed. +1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.