Hot questions for Using Enterprise JavaBeans in session

Question:

Based on this Jaspic Example I wrote the following validateRequest method for a ServerAuthModule:

public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject,
        Subject serviceSubject) throws AuthException {

    boolean authenticated = false;
    final HttpServletRequest request = 
                      (HttpServletRequest) messageInfo.getRequestMessage();
    final String token = request.getParameter("token");
    TokenPrincipal principal = (TokenPrincipal) request.getUserPrincipal();

    Callback[] callbacks = new Callback[] {
            new CallerPrincipalCallback(clientSubject, (TokenPrincipal) null) };

    if (principal != null) {
        callbacks = new Callback[] { 
                new CallerPrincipalCallback(clientSubject, principal) };
        authenticated = true;
    } else {
        if (token != null && token.length() == Constants.tokenLength) {
            try {
                principal = fetchUser(token);
            } catch (final Exception e) {
                throw (AuthException) new AuthException().initCause(e);
            }
            callbacks = new Callback[]
                        { 
                             new CallerPrincipalCallback(clientSubject, principal),
                             new GroupPrincipalCallback(clientSubject,
                                                        new String[] { "aRole" })
                        };
            messageInfo.getMap().put("javax.servlet.http.registerSession", "TRUE");
            authenticated = true;
        }
    }

    if (authenticated) {
        try {
            handler.handle(callbacks);
        } catch (final Exception e) {
            throw (AuthException) new AuthException().initCause(e);
        }
        return SUCCESS;
    }

    return AuthStatus.SEND_FAILURE;
}

This works as expected, for the first call of an ejb with @RolesAllowed("aRole") but for the next call this does not work at all. Wildfly denies it with this error message:

ERROR [org.jboss.as.ejb3.invocation] (default task-4) WFLYEJB0034: EJB Invocation 
    failed on component TestEJB for method public java.lang.String 
    com.jaspic.security.TestEJB.getPrincipalName():
    javax.ejb.EJBAccessException: WFLYSEC0027: Invalid User

If I guess right, the error occures in: org.jboss.as.security.service.SimpleSecurityManager line 367 of wilfly's source code, due to line 405, in which credential is checked, but seems to be null.

This seems equal in Wildfly 8/9/10CR (other versions not tested).

Again I'm not sure, if I'm doing it wrong, or if this is the same bug as https://issues.jboss.org/browse/WFLY-4626 ? And is it a bug at all, or is it expected behavior?


Answer:

This sounds like a bug to me as well, as the caller identity (caller / group Principals) appears to be retained in subsequent calls to the web, yet not to the EJB container. My own JASPIC classes (which function properly on GlassFish 4.1) fail for the same reason on WildFly 9.0.2.Final and 10.0.0.CR4 when used along with a plain Servlet and an SLSB, even with the latter marked @PermitAll.

As I'm myself unfamiliar with WildFly security internals I can not assist you in that respect. Unless you can get this patched, the sole SAM-level workaround I can think of for the time being would be to not use the javax.servlet.http.registerSession callback property that seemingly triggers the problem, but instead have the CallbackHandler register both the caller Principal and its groups on every validateRequest(...) invocation. If applicable to your use case, you may wish to attach that information to the HttpSession so as to speed up the process a bit; otherwise repeat from scratch. So, for example:

public class Sam implements ServerAuthModule {

    // ...

    @Override
    public AuthStatus validateRequest(MessageInfo mi, Subject client, Subject service) throws AuthException {
        boolean authenticated = false;
        boolean attachAuthnInfoToSession = false;
        final String callerSessionKey = "authn.caller";
        final String groupsSessionKey = "authn.groups";
        final HttpServletRequest req = (HttpServletRequest) mi.getRequestMessage();
        TokenPrincipal tp = null;
        String[] groups = null;
        String token = null;
        HttpSession hs = req.getSession(false);
        if (hs != null) {
            tp = (TokenPrincipal) hs.getAttribute(callerSessionKey);
            groups = (String[]) hs.getAttribute(groupsSessionKey);
        }
        Callback[] callbacks = null;
        if (tp != null) {
            callbacks = new Callback[] { new CallerPrincipalCallback(client, tp), new GroupPrincipalCallback(client, groups) };
            authenticated = true;
        }
        else if (isValid(token = req.getParameter("token"))) {
            tp = newTokenPrincipal(token);
            groups = fetchGroups(tp);
            callbacks = new Callback[] { new CallerPrincipalCallback(client, tp), new GroupPrincipalCallback(client, groups) };
            authenticated = true;
            attachAuthnInfoToSession = true;
        }
        if (authenticated) {
            try {
                handler.handle(callbacks);
                if (attachAuthnInfoToSession && ((hs = req.getSession(false)) != null)) {
                    hs.setAttribute(callerSessionKey, tp);
                    hs.setAttribute(groupsSessionKey, groups);
                }
            }
            catch (IOException | UnsupportedCallbackException e) {
                throw (AuthException) new AuthException().initCause(e);
            }
            return AuthStatus.SUCCESS;
        }
        return AuthStatus.SEND_FAILURE;
    }

    // ...

    @Override
    public void cleanSubject(MessageInfo mi, Subject subject) throws AuthException {
        // ...
        // just to be safe
        HttpSession hs = ((HttpServletRequest) mi.getRequestMessage()).getSession(false);
        if (hs != null) {
            hs.invalidate();
        }
    }

    private boolean isValid(String token) {
        // whatever
        return ((token != null) && (token.length() == 10));
    }

    private TokenPrincipal newTokenPrincipal(String token) {
        // whatever
        return new TokenPrincipal(token);
    }

    private String[] fetchGroups(TokenPrincipal tp) {
        // whatever
        return new String[] { "aRole" };
    }

}

I tested the above on the aforementioned WildFly versions and in the aforementioned fashion (i.e. with a single Servlet referencing a single SLSB marked @DeclareRoles / method-level @RolesAllowed) and it seems to work as expected. Obviously I cannot guarantee that this approach will not fail in other unexpected ways.


See also:

Question:

I have an @EJB injected bean TransactionCompleteJob. This bean has an @Asynchronous method on it asyncCompleteTransaction(Integer transactionId).

When I try to make use of other injected beans and entities that are either session scoped or conversation scoped within this method I end up getting an error:

WELD-001303: No active contexts for scope type javax.enterprise.context.ConversationScoped

So I Injected weld's BoundConversationScope, BoundSessionScope, and BoundRequestScope and activated them, generating an empty map for the request data, and an empty map for the session data, as specified by jboss weld documentation:

The problem is that when activating the request scope I get another error message:

WELD-001304: More than one context active for scope type javax.enterprise.context.RequestScoped

I've tried not activating the request scope, but I seem to end up with a resource leak of anything which was on the actual request scope, specifically I have a request scoped JPA EntityManager. In particular once the process finishes I see another message:

WELD-000019: Error destroying an instance org.hibernate.jpa.internal.EntityManagerImpl@5df070be of Producer Method [EntityManager] with qualifiers [@RequestScopey @Any] declared as [[BackedAnnotatedMethod] @Produces @RequestScoped @RequestScopey public packagename.entitymanager.EntityManagerProducer.createRequestScopedEntityManager()]

How can I start a Request Scope Context when I have one already active? Or start a Session Scope Context and Conversation Scope Context which tie in to the existing Request Scope Context? Alternatively, are there any better ways to get around this issue?

EDIT:

Is there any way to get hold of the RequestScope from weld so I can deactivate it, before starting my own? Or a way to Asynchronously start my TransactionCompleteJob asynchronously, without injecting it and calling the @Asynchronous method?


Answer:

I had more or less the same problem but took a different approach: I had a @ConversationScoped EntityManager injected in my repositories but then I needed to do some batch processing where no ConversationContext was available and got exceptions when using my repositories. Instead of trying to activate the ConversationContext where it was not meant to be used, I ended implementing 2 new contexts (+ 1 interceptor):

  • the first one was a ThreadContext (@ThreadScoped) which stored everything in a Map in a ThreadLocal (which is nice for async processing) + 1 method interceptor (@ThreadContextual) to be used on my async/batch methods to activate this context for the time of the invocation.
  • the second one was a bit more complicated: it was some sort of dynamic context which delegated to the first active context in that order: ThreadContext, (NonTransient)ConversationContext, (NonTransient)ViewContext (@ViewScoped from JSF 2.2), RequestContext. I called this context UnitOfWorkContext with the corresponding @UnitOfWorkScoped annotation. I annotated the (few) beans that needed to live in that context (for me, it was only the @Produces method for myEntityManager).

It can seem difficult to implement all of this but it's not, the code was pretty small. If needed, I will paste my code in 2-3 days as I don't have access to it for the moment.

UPDATE: Here is the code for the 2nd context:

The following interface is used as a complement to Context.isActive(). Sometimes, even if a context is active, it does not mean I want to use it, see below for an example.

public interface DynamicContextActivation {

    boolean isActive(Context context);
}

The following annotation should be put on your new scope

@Retention(RUNTIME)
@Target(ANNOTATION_TYPE)
public @interface DynamicScope {

    class DefaultActivation implements DynamicContextActivation {

        public boolean isActive(Context context) {
            return true;
        }
    }

    Class<? extends Annotation>[] value();

    Class<? extends DynamicContextActivation> activation() default DefaultActivation.class;
}

Implementation of dynamic context

public class DynamicContext implements AlterableContext {

    private final BeanManager beanManager;
    private final DynamicContextActivation activation;
    private final Class<? extends Annotation> scope;
    private final Class<? extends Annotation>[] scopes;

    public DynamicContext(BeanManager beanManager, DynamicContextActivation activation, Class<? extends Annotation> scope, Class<? extends Annotation>[] scopes) {
        this.beanManager = beanManager;
        this.activation = activation;
        this.scope = scope;
        this.scopes = scopes;
    }

    public void destroy(Contextual<?> contextual) {
        Context context = getContext();
        if (context instanceof AlterableContext) {
            ((AlterableContext) context).destroy(contextual);
        }
    }

    public <T> T get(Contextual<T> contextual) {
        return getContext().get(contextual);
    }

    public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) {
        return getContext().get(contextual, creationalContext);
    }

    // Find the first active context
    private Context getContext() {
        for (Class<? extends Annotation> scope : this.scopes) {
            try {
                Context context = this.beanManager.getContext(scope);
                if (context.isActive() && this.activation.isActive(context)) {
                    return context;
                }
            } catch (ContextNotActiveException exception) {
                continue;
            }
        }
        return null;
    }

    public Class<? extends Annotation> getScope() {
        return this.scope;
    }

    public boolean isActive() {
        return getContext() != null;
    }
}

Extension that registers dynamic context automatically (add it to /META-INF/services/javax.enterprise.inject.spi.Extension)

public class DynamicContextExtension implements Extension {

    private final Set<Class<? extends Annotation>> scopes = new HashSet<>();

    public void processBean(@Observes ProcessBean<?> bean) {
        Class<? extends Annotation> scope = bean.getBean().getScope();
        if (scope.isAnnotationPresent(DynamicScope.class)) {
            this.scopes.add(scope);
        }
    }

    public void afterBeanDiscovery(@Observes AfterBeanDiscovery afterBeanDiscovery, BeanManager beanManager) {
        for (Class<? extends Annotation> scope : scopes) {
            DynamicScope dynamicScope = scope.getAnnotation(DynamicScope.class);
            try {
                // TODO use a managed DynamicContextActivation instead of instantiating it here
                DynamicContextActivation activation = dynamicScope.activation().newInstance();
                Context context = new DynamicContext(beanManager, activation, scope, dynamicScope.value());
                afterBeanDiscovery.addContext(context);
            } catch (InstantiationException | IllegalAccessException exception) {
                afterBeanDiscovery.addDefinitionError(exception);
            }
        }
    }
}

This scopes delegates in order to ThreadScoped, (LongRunning)ConversationScoped, (NonTransient)ViewScoped, RequestScoped:

@Retention(RUNTIME)
@NormalScope(passivating = true) // must be true if any of the delegate context is passivation-capable
@DynamicScope(value = {ThreadScoped.class, ConversationScoped.class, ViewScoped.class, RequestScoped.class}, activation = UnitOfWorkActivation.class)
public @interface UnitOfWorkScoped {

    class UnitOfWorkActivation implements DynamicContextActivation {

        public boolean isActive(Context context) {
            if (context.getScope().equals(ConversationScoped.class)) {
                // I only want long-running conversations here because in JSF there
                // is always a transient conversation per request and it could take
                // precedence over all other scopes that come after it
                return !CDI.current().select(Conversation.class).get().isTransient();
            }
            if (context.getScope().equals(ViewScoped.class)) {
                // Storing things in view scope when the view is transient gives warnings
                return !FacesContext.getCurrentInstance().getViewRoot().isTransient();
            }
            return true;
        }
    }
}

An EntityManager producer which gives @UnitOfWorkScoped EntityManagers:

@Stateful // it could work without @Stateful (but Serializable) but I haven't tested enough
@UnitOfWorkScoped
public class EntityManagerProducer {

    @PersistenceContext(type = EXTENDED)
    private EntityManager entityManager;

    @Produces
    @UnitOfWorkScoped
    @TransactionAttribute(NOT_SUPPORTED)
    public EntityManager entityManager() {
        return entityManager;
    }
}

There is surely room for improvement so don't hesitate to give your feedback.

UPDATE 2: it would be nice to replace DynamicContextActivation with EL expressions

@Retention(RUNTIME)
@NormalScope(passivating = true)
@DynamicScope({
    @Scope(scope = ThreadScoped.class),
    @Scope(scope = ConversationScoped.class, ifExpression = "#{not javax.enterprise.context.conversation.transient}"),
    @Scope(scope = ViewScoped.class, ifExpression = "#{not facesContext.viewRoot.transient}"),
    @Scope(scope = RequestScoped.class)
})
public @interface UnitOfWorkScoped {}

Question:

I am using the following JNDI configuration:

    final String appName = "";
    final String moduleName = "session-beans";
    final String distinctName = "";
    final String beanName = "ItemStatefulRemote";
    final String viewClassName = ItemStatefulRemote.class.getName();
    final String toLookup = String.format("ejb:%s/%s/%s/%s!%s", appName, moduleName, distinctName, beanName, viewClassName);
    return (ItemStatefulRemote) context.lookup(toLookup);

While trying to connect with a stateful bean I am getting the following error:

Session id hasn't been set for stateful component:

What can be the reason?


Answer:

Since it is a stateful bean so will have to add the session id which can be done by using the annotation ?stateful along with the viewClassName.

So the code should be changed to:

 final String viewClassName = ItemStatefulRemote.class.getName()+"?stateful";

Question:


Answer:

Java EE Servers or Java Servlet containers have a public static void main method which starts up the program. After that, most servers allocate a certain number of threads that listen and handle requests

Question:

When using a Stateful EJB, how does the server know who the EJB is associated with if the client does not have an active session? I have used stateless EJB's before, but am now trying to learn how to use stateful EJB's. I was thinking of implementing my shopping cart as a stateful EJB, instead of having a POJO Cart that I add as an attribute in the user's session. But since a Stateful EJB isn't explicitly added as an attribute in the HttpSession, how does the server associate the client with the stateful EJB?


Answer:

The EJB doesn't technically need to have access to the JSESSION_ID of the client because, like any basic pojo, it's alive and usable, as long as the calling client is alive. Once the calling client is destroyed or otherwise relinquishes control of the SFSB, the bean is liable to be passivated or destroyed (and hence "forget" the conversation)

From the Oracle JavaEE-6 tutorial

The state is retained for the duration of the client/bean session. If the client removes the bean, the session ends and the state disappears. This transient nature of the state is not a problem, however, because when the conversation between the client and the bean ends, there is no need to retain the state

Think of it the same way you get hold of a regular java object in a has-a relationship: once you've set the composed object to null, you've basically ended your conversation with that object. The same applies here (sort of). There's no need for the client to pass specific session information to the EJB. The EJB's normal lifecycle and annotations (specifically @Remove) take care care of everything else.

A word of caution about SFSBs: They are heavyweight and they last longer than SLSBs. Don't use them unless you really need a full-scale EJB's trappings. In many cases, a plain HttpSession and an SLSB would suffice.

Further Reading

Question:

In Wildfly 10 standalone mode I am getting SessionContext object using below snippet

InitialContext context = new InitialContext();
UserTransaction userTrans = null;
userTrans = (UserTransaction) m_Context.lookup("java:jboss/UserTransaction");
userTrans.setTransactionTimeout(600000);

then in SLSB I use

@Resource
protected SessionContext sessionontext;

But same code when executed in DOMAIN mode it fails to use SessionContext as its value is null.

Update

@Stateless(mappedName="AppManager")
@Local(value = AppManager.class)
@Remote(value = AppManagerRemote.class)
@TransactionAttribute(TransactionAttributeType.REQUIRED)
@TransactionManagement(TransactionManagementType.CONTAINER)


    public class AppManagerBean extends AppManagerAdapter implements AppManagerRemote
    {
      try
      {
      }
      catch(Exp..)
      {
        sessionontext.setRollbackOnly();  ///Here sessionontext is null
      }
    }

    public class AppManagerAdapter
    {
        @Resource
        protected SessionContext sessionontext;
    //
    }

Answer:

SessionContext injection should be in the stateless bean itself . So moved

@Resource
        protected SessionContext sessionontext;

from AppManagerAdapter to AppManagerBean then it worked.

Question:

I have some utility functions which may be called from multiple Stateless Session EJBs. These utility functions needs to be in a new transaction (RequiresNew).

Does it make sense to create one Stateless Session EJB for all these functions may be call it Utility?

Or should I try to have them organized by functionality in which case I will end up with multiple Stateless Session EJBs? What will be the impact on performance of system if I have lot of such Stateless Session EJBs?

Some examples of utility functions:

  • I have a table where I store messages with Id. Create a utility function to retrieve a message for a specific Id. Create a utility function to update a message for a specific Id.

  • I have a table where I keep track of statuses of some processes. Create a utility function to give status of a specific Process. Create a utility function to update status of a specific Process.

etc.


Answer:

From a performance point of view, for every stateless EJB, the container must instantiate and manage a bean pool containing instances of that bean. (This typically isn't large, since stateless beans can be used interchangeably. I believe the default in JBoss AS is 20 instances/pool) If you combine these into a single bean, only one pool is required, but it will probably need more instances, since they must serve all the types of call. So performance isn't going to be affected noticeably.

I much bigger problem is encapsulation - having a "utility" session bean would entirely violate separation of concerns, it would leave you with one class with many different purposes and dependencies. It risks becoming a Ball of Mud, will mix dependencies for all the methods, and it will make your code harder to maintain, since it is harder to work out where these functions are.

I'd highly recommend thinking more about whether there are meaningful functional units to separate these methods into, even if they are each quite small. As other commenters have suggested, your two examples sound like good candidates for a ProcessService and a MessageService. You may find that when you look at the sets of functionality you want to add that these aren't the best way to divide things up, but it's probably a good starting point. If you put in the effort now to identify what the distinct logical services are in your system, you'll reap the rewards in extensibility and maintainability later.

Question:

As per the Netbeans Tutorial on EJB Client applications, I cannot seem to invoke the method:

compile error:

-do-compile:
    [mkdir] Created dir: /home/thufir/NetBeansProjects/EntAppClient/build/empty
    [mkdir] Created dir: /home/thufir/NetBeansProjects/EntAppClient/build/generated-sources/ap-source-output
    [javac] Compiling 1 source file to /home/thufir/NetBeansProjects/EntAppClient/build/jar
    [javac] /home/thufir/NetBeansProjects/EntAppClient/src/java/entappclient/Main.java:16: error: cannot find symbol
    [javac]         System.err.println("result = " + mySession.getResult());
    [javac]                                                   ^
    [javac]   symbol:   method getResult()
    [javac]   location: variable mySession of type MySessionRemote
    [javac] 1 error

BUILD FAILED

client:

package entappclient;

import ejb.MySessionRemote;
import javax.ejb.EJB;

public class Main {

    @EJB
    private static MySessionRemote mySession;

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {

        System.err.println("result = " + mySession.getResult());

    }

}

ejb:

package ejb;

import javax.ejb.Stateless;

@Stateless
public class MySession implements MySessionRemote {

    public String getResult() {
        return "This is My Session Bean";
    }
}

remote interface:

package ejb;

import javax.ejb.Remote;

@Remote
public interface MySessionRemote {

}

now, if the interface is modified:

package ejb;

import javax.ejb.Remote;

@Remote
public interface MySessionRemote {

    public String getResult();
}

the bean can now @Override the method:

package ejb;

import javax.ejb.Stateless;

@Stateless
public class MySession implements MySessionRemote {

    @Override
    public String getResult() {
        return "This is My Session Bean";
    }
}

however, there's a NPE:

-run:
     [java] java.lang.reflect.InvocationTargetException
     [java]     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     [java]     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
     [java]     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
     [java]     at java.lang.reflect.Method.invoke(Method.java:606)
     [java]     at org.glassfish.appclient.client.acc.AppClientContainer.launch(AppClientContainer.java:446)
     [java]     at org.glassfish.appclient.client.AppClientFacade.main(AppClientFacade.java:166)
     [java] Caused by: java.lang.NullPointerException
     [java]     at entappclient.Main.main(Main.java:16)
     [java]     ... 6 more
     [java] Java Result: 1

run:

BUILD SUCCESSFUL
Total time: 18 seconds
thufir@dur:~/NetBeansProjects/EntAppClient$ 

How can I invoke the method correctly? The EJB isn't instantiated?


Answer:

I started from scratch. The only difference I can think of is that instead of making an EJB application, I just made an EJB module for the bean. Otherwise, I think it's the same.

structure:

thufir@dur:~/NetBeansProjects$ 
thufir@dur:~/NetBeansProjects$ tree HelloLibrary/
HelloLibrary/
├── build.xml
├── nbproject
│   ├── build-impl.xml
│   ├── genfiles.properties
│   ├── private
│   │   └── private.properties
│   ├── project.properties
│   └── project.xml
└── src
    └── hello
        └── HelloBeanRemote.java

4 directories, 7 files
thufir@dur:~/NetBeansProjects$ 
thufir@dur:~/NetBeansProjects$ tree HelloEJB/
HelloEJB/
├── build.xml
├── nbproject
│   ├── ant-deploy.xml
│   ├── build-impl.xml
│   ├── genfiles.properties
│   ├── private
│   │   └── private.properties
│   ├── project.properties
│   └── project.xml
└── src
    ├── conf
    │   └── MANIFEST.MF
    └── java
        └── hello
            └── HelloBean.java

6 directories, 9 files
thufir@dur:~/NetBeansProjects$ 
thufir@dur:~/NetBeansProjects$ tree HelloClient/
HelloClient/
├── build.xml
├── nbproject
│   ├── ant-deploy.xml
│   ├── build-impl.xml
│   ├── genfiles.properties
│   ├── private
│   │   └── private.properties
│   ├── project.properties
│   └── project.xml
├── src
│   ├── conf
│   │   ├── application-client.xml
│   │   └── MANIFEST.MF
│   └── java
│       └── helloclient
│           └── Main.java
└── test

7 directories, 10 files
thufir@dur:~/NetBeansProjects$ 
thufir@dur:~/NetBeansProjects$ 

client code:

package helloclient;

import hello.HelloBeanRemote;
import javax.ejb.EJB;

public class Main {
    @EJB
    private static HelloBeanRemote helloBean;

    public static void main(String... args) {
        System.out.println(helloBean.Hi());
    }

}

bean:

package hello;

import javax.ejb.Stateless;

@Stateless
public class HelloBean implements HelloBeanRemote {

    @Override
    public String Hi() {
        return "hello world";
    }

    @Override
    public String Bye() {
        return "goodbye";
    }

}

remote interface:

package hello;

import javax.ejb.Remote;

@Remote
public interface HelloBeanRemote {
    public String Hi();
    public String Bye();
}

Question:

I have the following design. When a client makes a request to the server, the server creates a state that holds all sorts of info. There are various stateless and stateful beans which need to read and write to this state. Refer to this unprofessional diagram:

The ComputationCycle class is where the processing starts and works by phases. During each phase it calls upon other Manager classes (which behave like utility classes) to help in the computation (diagram shows only for 1 phase). The state is being read and written to both from the CC class and the managers, both are stateless.

State holds Employee, Department and Car classes (in some irrelevant data structure) which are stateful. These classes can also call the Manager classes. This is done by a simple @Inject Manager1. The same way CC uses managers.

My problem is how to access the stateful state (and its contained classes) from the stateless classes (and from the Car, Department and Employee classes too, although I think solving one will solve the other). I can't inject a stateful bean into a stateless bean. So after the client makes a request and the computation cycle starts, how do I access the state related to this request?

One solution is to pass the state to every method in the stateless classes, but this is really cumbersome and bloaty because all methods will have an "idiotic" State argument everywhere.

How can I make this design work the way I want it to?


Answer:

I can't inject a stateful bean into a stateless bean.

You can absolutely inject dependencies this way.

If the stateful bean is @RequestScoped, any call into the stateless bean on that thread that hits a CDI injected contextual reference (iow proxy) will find its way to the right instance of the stateful bean.

As long as you use CDI, you don't need to trouble yourself with trying to stash things away in your own threadlocals.

Question:

I am migrating Ejb 2.1 to Ejb 3.1. I changed Java Version from 1.6 to 1.8, and Ejb Version from 2.1 to 3.1. Once I made the changes, I am getting problems in the ibm-ejb-jar-bnd.xml and ibm-ejb-jar-ext.xml files. I am getting these messages:

1: Session EJB with name 'abcEJB' not found 2: Resource reference with name 'ResourceRef_xyz' not found for this EJB or interceptor

Am I missing anything?



Answer:

I have migrated from EJB 2.1 to EJB 3.1 couple of years back and I recall facing the same issues and error you are facing.

Although I don't remember the exact action that fixed the issue nor other issues I faced along the way, but I will tell you what I did to fix ALL issues, including this one.

Note: It's not an easy task to migrate, but following these next steps as described will save you lots of hassle later on.

  1. Annotate session beans and interfaces with proper annotations: In my case I had remote interfaces for EJB 2.1 beans. Since I did not need an actual remote interface in my application, I switched them into local interfaces.
  2. Empty ibm-ejb-jar-bnd.xml and ibm-ejb-jar-ext.xml
  3. Change clients to lookup either using DI, JNDI name. In my case I used JNDI lookup.

Now the code should look like this:

Session Bean interface:

@Local
public interface MySessionInterface {
    // TODO :: declare business methods
}

Session bean implementation:

@stateless
public interface MySessionBeanImpl implements MySessionInterface {
    // TODO :: implement business methods
}

Service Locator to lookup EJBs using JNDI:

public class ServiceLocator {
    public final <T> T getLocalSession(Class<T> _class) throws NamingException {
        return (T) new InitialContext().lookup("ejblocal:" + _class.getName());
    }
}

Client:

public class SessionClient {
     public void performOperation() {
         try {
            MySessionInterface session = ServiceLocator.getLocalSession(MySessionInterface.class);
            // TODO :: perform business logic here
        } catch (NamingException e) {
             // TODO :: handle exception
        }
    }
}

Of course service locator can have the following improvements but I removed them for brevity:

  • Cache the result instead of looking it up everytime from the JNDI
  • Catch the checked exception NamingException and throw your own runtime exception

Hope you find it useful.

Question:

UPDATE QUESTION:

I used JBOSS Develper Studio 8, JBOS server 7.1 based on jre 1.7 I have one J2EE project with ejb and web projects. In ejb project I have two identical ejb 3.1 In web project I have only one servlet. This servlet call simple test method in first ejb and then in second ejb. First thing in test method is dependency injection for resource session context via this code

@Resource
private SessionContext context;

First ejb works ok, but second (and any following) return null for session context. This is the comlete code:

FirstServlet.java

@WebServlet("/FirstServlet")
public class FirstServlet extends HttpServlet {
private static final long serialVersionUID = 1L;

@EJB
FirstEJB firstEJB = new FirstEJB();
SecondEJB secondEJB = new SecondEJB();
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    PrintWriter out = response.getWriter();
    out.println(firstEJB.helloFirst());
    out.println(secondEJB.helloSecond());   
}
}

FirstEJB.java

@Stateless
public class FirstEJB {

@Resource
private SessionContext contextFirst;

public String helloFirst(){

    System.err.println(contextFirst.toString());

    return "Hello from FirstEJB";    

 }
}

SecondEJB.java

@Stateless
public class SecondEJB {

@Resource
private SessionContext contextSecond;

public String helloSecond(){

   System.err.println(contextSecond.toString());    

   return "Hello from SecondEJB";    

 }
}

Can anybody knows where is the problem.


Answer:

The first rule for using injection is that your server (otherwise known as the "container") creates the objects that you inject.

In your case the lifecycle of each EJB instance is under the complete control of the container.

In your code, the firstEJB instance that is created by you is replaced by another instance that is created by the container. The secondEJB instance remains the one created by you (it's missing the @EJB annotation), so it has not been subjected to proper lifecycle management and has not been fully constructed with it's @Resource injection processed.

Therefore, a simple change to your servlet code:

@WebServlet("/FirstServlet")
public class FirstServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    @EJB
    private FirstEJB firstEJB;

    @EJB
    private SecondEJB secondEJB;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        PrintWriter out = response.getWriter();
        out.println(firstEJB.helloFirst());
        out.println(secondEJB.helloSecond());   
    }
}

should give you the desired result.

Question:

In EJB SessionBean, I set the transaction time out to 3600 seconds. And I have a loop code which may use this sessionbean. After 3600 seconds, the sessionbean is transaction time out, but the loop is still working. My question is that when go to the next loop after the transaction time out, will a new transaction for sessionbean be created? Or any information about the transaction used here?

SessionBean xx = ...;
while(...){ // This loop may be a long time more than 3600s
    try{
        xx.do();
    }catch(Exception e){
    }
}
// if xx is transaction time out, the while loop is still working, then will a new transaction for xx be created?

Answer:

It depends. If e.g. SessionBean#do() is annotated with

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void do() { ...

then for each call of do() a new transaction will be opened.

If e.g. SessionBean#do() is annotated with

@TransactionAttribute(TransactionAttributeType.REQUIRES)
public void do() { ...

and your loop-method has already an open transaction, because it is annotated like this:

@TransactionAttribute(TransactionAttributeType.REQUIRES) // or REQUIRES_NEW
public void loopMethod() { ...

then the whole transaction is broken.

For TransactionAttributes see https://docs.oracle.com/html/E13981_01/servtran002.htm

Question:

I'm using wildfly and have a problem with EJB events and @Observes annotation.

I have an @ApplicationScoped bean, which is instanciated twice. Any idea why?

@ApplicationScoped
public class WmsUiCodeService implements Serializable {
    private static final long serialVersionUID = 3051136197752781297L;

    ....

    @Override
    public void handleChangeEvent(@Observes MychangeEvent event) {
        ...
    }
}

I use it once from a sessionScoped bean and once from a resquestScoped bean:

@Inject
private UiCodeService uiCodeService;

My first problem is that i have 2 instances of this bean and the second is that the handleChangeEvent is called just in one of those two instances.


Answer:

I found the problem. It comes from the annotation which came from

javax.faces.bean.ApplicationScoped

if i use the one in

javax.enterprise.context.ApplicationScoped

than is everything ok.

Question:

I'm developing a Sign up operation, where the user enter his email and password press the submit(createUser method) button, User entity get persisted AND set the id of User in HttpSession, next he moved to next jsf where enter information for School Object (Entity). My problem is that the User get persisted BUT the School is not. here is my code:

public CreateBn() {
    user = new User();
    school = new School();
    adress = new Adresse();
    school.setAdresse(adress);
    facesContext = FacesContext.getCurrentInstance();
    session = (HttpSession) facesContext.getExternalContext().getSession(false);
}

public String createUser() {
    initialiserDateInscription();
    session.setAttribute("UserId", user.getId());
    //System.out.println((BigInteger) session.getAttribute("UserId"));
    userPr.createUser(user);
    return SHCOOL_INSCRIPTION;
}

public String createSchool() {
    BigInteger userId = (BigInteger) session.getAttribute("UserId");
    System.out.println("MEHDI : " + userId);
    try {
        User userTemp = userPr.getUserById(userId);// Here is the problem 
        school.setUser(userTemp);
    } catch (Exception e) {
        e.printStackTrace();
    }
    session.setAttribute("SchoolId", school.getId());
    school.setAdresse(adress);
    schoolPr.createSchool(school);
    return INSCRIPTION_RETURN;
}

as you can see I get the User entity based on the UserId saved in session, but I get nothing, it says:

javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.

any more info, I'm here. So how can I solve this??

@Entity
@Table(schema = "school", name = "school")
public class School implements Serializable {

private static final long serialVersionUID = 1L;

@Id
private BigInteger id;

private String name;

@OneToOne(fetch=FetchType.EAGER)
@JoinColumn(name = "userId")
private User user;

@OneToOne(fetch=FetchType.LAZY, cascade=CascadeType.PERSIST)
@JoinColumn(name = "adressId")
private Adresse adresse;

EJB

@Stateless
public class UserPr {

@PersistenceContext(unitName = "proj")
private EntityManager em;


public void createUser(User user) throws RuntimeException{
    try {
        em.persist(user);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

public User getUserById(BigInteger UserId) throws Exception{
    try{
        return em.createNamedQuery("User.findById", User.class).setParameter("id", UserId).getSingleResult();
    }catch(Exception e){
        e.printStackTrace();
    }
    return null;
}

}

@NamedQueries({
@NamedQuery(name="User.findById", query="SELECT u FROM User u WHERE u.id = :id")
})
public class User implements Serializable {

Answer:

Try changing the way you get and set the userId.

instead of this line

session.setAttribute("UserId", user.getId());

try this

ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
Map<String, Object> sessionMap = externalContext.getSessionMap();
sessionMap.put("UserId", user.getId());

and instead of this

BigInteger userId = (BigInteger) session.getAttribute("UserId");

try this

BigInteger userId  = (BigInteger) sessionMap.get("UserId");