Hot questions for Using Enterprise JavaBeans in singleton

Question:

I have a java EE project that is executed in a Glassfish 4.1 container using Eclipse Mars, using EJB injection. I have a Singleton EJB that initialize or update the database when application start

@Startup
@Singleton
public class DatabaseUpdater {

    private static final Logger LOG = Logger.getLogger(DatabaseUpdater.class.getName());

   /**
    * Initializes database process
    */
    @PostConstruct
    public void initialize(UserVO userVO) {
        // ... initialize code
    }
}

The project is executed in Eclipse Mars, using Debug on Server option, and it was working good. However yesterday I just tried to do this to start project, and deployment process failed in Eclipse. This exception stack appears:

2016-02-21T11:03:52.001-0500|Grave: Exception during lifecycle processing
javax.ejb.EJBException: javax.ejb.CreateException: Initialization failed for Singleton DatabaseUpdater
    at com.sun.ejb.containers.AbstractSingletonContainer$SingletonContextFactory.create(AbstractSingletonContainer.java:649)
    at com.sun.ejb.containers.AbstractSingletonContainer.instantiateSingletonInstance(AbstractSingletonContainer.java:389)
    at org.glassfish.ejb.startup.SingletonLifeCycleManager.initializeSingleton(SingletonLifeCycleManager.java:219)
    at org.glassfish.ejb.startup.SingletonLifeCycleManager.initializeSingleton(SingletonLifeCycleManager.java:180)
    at org.glassfish.ejb.startup.SingletonLifeCycleManager.doStartup(SingletonLifeCycleManager.java:158)
    at org.glassfish.ejb.startup.EjbApplication.start(EjbApplication.java:166)
    at org.glassfish.internal.data.EngineRef.start(EngineRef.java:122)
    at org.glassfish.internal.data.ModuleInfo.start(ModuleInfo.java:291)
    at org.glassfish.internal.data.ApplicationInfo.start(ApplicationInfo.java:352)
    at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:500)
    at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:219)
    at org.glassfish.deployment.admin.DeployCommand.execute(DeployCommand.java:491)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$2$1.run(CommandRunnerImpl.java:539)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$2$1.run(CommandRunnerImpl.java:535)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.Subject.doAs(Subject.java:360)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$2.execute(CommandRunnerImpl.java:534)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$3.run(CommandRunnerImpl.java:565)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$3.run(CommandRunnerImpl.java:557)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.Subject.doAs(Subject.java:360)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:556)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1464)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl.access$1300(CommandRunnerImpl.java:109)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1846)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1722)
    at com.sun.enterprise.v3.admin.AdminAdapter.doCommand(AdminAdapter.java:534)
    at com.sun.enterprise.v3.admin.AdminAdapter.onMissingResource(AdminAdapter.java:224)
    at org.glassfish.grizzly.http.server.StaticHttpHandlerBase.service(StaticHttpHandlerBase.java:189)
    at com.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:459)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:167)
    at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:201)
    at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:175)
    at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:235)
    at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:284)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:201)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:133)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:112)
    at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
    at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:561)
    at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:117)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:56)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:137)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:565)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:545)
    at java.lang.Thread.run(Thread.java:745)
Caused by: javax.ejb.CreateException: Initialization failed for Singleton DatabaseUpdater
    at com.sun.ejb.containers.AbstractSingletonContainer.createSingletonEJB(AbstractSingletonContainer.java:476)
    at com.sun.ejb.containers.AbstractSingletonContainer.access$000(AbstractSingletonContainer.java:74)
    at com.sun.ejb.containers.AbstractSingletonContainer$SingletonContextFactory.create(AbstractSingletonContainer.java:647)
    ... 47 more
Caused by: java.lang.IllegalArgumentException: wrong number of arguments
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.sun.ejb.containers.interceptors.BeanCallbackInterceptor.intercept(InterceptorManager.java:1035)
    at com.sun.ejb.containers.interceptors.CallbackChainImpl.invokeNext(CallbackChainImpl.java:72)
    at com.sun.ejb.containers.interceptors.CallbackInvocationContext.proceed(CallbackInvocationContext.java:205)
    at org.jboss.weld.ejb.AbstractEJBRequestScopeActivationInterceptor.aroundInvoke(AbstractEJBRequestScopeActivationInterceptor.java:55)
    at org.jboss.weld.ejb.SessionBeanInterceptor.aroundInvoke(SessionBeanInterceptor.java:52)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.sun.ejb.containers.interceptors.CallbackInterceptor.intercept(InterceptorManager.java:986)
    at com.sun.ejb.containers.interceptors.CallbackChainImpl.invokeNext(CallbackChainImpl.java:72)
    at com.sun.ejb.containers.interceptors.CallbackInvocationContext.proceed(CallbackInvocationContext.java:205)
    at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.doCall(SystemInterceptorProxy.java:163)
    at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.init(SystemInterceptorProxy.java:125)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.sun.ejb.containers.interceptors.CallbackInterceptor.intercept(InterceptorManager.java:986)
    at com.sun.ejb.containers.interceptors.CallbackChainImpl.invokeNext(CallbackChainImpl.java:72)
    at com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:412)
    at com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:375)
    at com.sun.ejb.containers.BaseContainer.intercept(BaseContainer.java:2014)
    at com.sun.ejb.containers.AbstractSingletonContainer.createSingletonEJB(AbstractSingletonContainer.java:468)
    ... 49 more

Someone knows how to fix this error? After this happen, the DAS of glassfish try again to deploy application, and eclipse generate several times deployment error messages (this only stop when I remove the resource in glassfish server and stop it)

The project is using maven to manage dependencies.


Answer:

As specified in the docs:

The method on which the @PostConstruct annotation is applied MUST fulfill all of the following criteria

  • The method MUST NOT have any parameters except in the case of EJB interceptors in which case it takes an InvocationC ontext object as defined by the EJB specification.
  • The return type of the method MUST be void.
  • The method MUST NOT throw a checked exception.
  • The method on which PostConstruct is applied MAY be public, protected, package private or private.
  • The method MUST NOT be static except for the application client.
  • The method MAY be final.
  • If the method throws an unchecked exception the class MUST NOT be put into service except in the case of EJBs where the EJB can handle exceptions and even recover from them.

Then change your method from

@PostConstruct
public void initialize(UserVO userVO) {
    // ... initialize code
}

to

@Inject
UserVO userVO

@PostConstruct
public void initialize() {
    // ... initialize code
}

and create a producer that will be responsible to provide the UserVo object to the injection points with the @Produces annotation.

Question:

my problem is that the @PostConstruct is called twice even though it shouldn't. I searched a lot and found similiar problems with jersey https://java.net/jira/browse/JERSEY-1883?filter=-3. However I tried to make a small example which apparently still causes the problem even without any clatter.

import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
import javax.ejb.Startup;

@Singleton
@Startup
public class TestSingleton {

  @PostConstruct
  public void init() {
    System.out.println("How many times am I being called?");
  }
}

Configuration

  • Application server: Glassfish 3.1.2
  • Java Version: JDK 1.7_17
  • Packaging: A war file within an ear

Any ideas?


Answer:

I figured it out by using @PreDestroy or Publish of the application server.

The problem is "normal". With using Eclipse as an IDE after the server start the application will be published again. Therefore you'll only see one log message of @PreDestroy but two of @PostConstruct.

The same goes for changing something and publishing afterwards. Here you should only see the message from @PostConstruct once.

Then you'll know everything is alright.

Question:

I have a thread safe heavy resource and I would like to initialize this as a static class variable. During initializing this object I need to read some "connection" parameters from external property file.

To read the init parameters I would like to use my exicting Configuration Singleton EJB but it seems that my injected configuration bean is null at deployment time (when EE container initializes my static variable).

This is my Configuration EJB:

@Startup
@Singleton
@LocalBean
public class Configuration {

    @Lock(LockType.READ)
    public String getValue(String key) {
        return ...;
    }
}

This is the way how I would like to initialize my HeavyObject:

@Stateless
public class SenderBean {

    private static HeavyObject something;

    @Inject
    private Configuration configuration;

    public SendNotificationBean()  {
        String host = configuration.getValue("....");
        String port= configuration.getValue("....");

        something = new HeavyObject(host, port);
    }
}

But configuration is null:

Caused By: java.lang.NullPointerException
        at com.aaa.bbb.business.SenderBean.configureProxy(SenderBean.java:187)

Maybe I need to change the order how container initializes EJB-s?


Answer:

It will not work since the container calls the default constructor before it injects anything. There is an annotation @PostConstruct for that.

To get around this I would also make HeavyObject a singleton bean and inject Configuration in it. Something like:

@Singleton
public class HeavyObject {

    @Inject
    private Configuration conf;

    @PostConstruct
    private void configure() {
        // make something with the conf
    }

}

and inject it:

@Stateless
public class SenderBean {

    @Inject
    private HeavyObject ho;
    ...
}

Of course this is just only one way to do it but I would recommend to avoid static stuff in beans and think carefully what is in the beans responsibility. That is why I have put the @PostConstruct configuration logic to HeavyObject singleton instead of running it on the SenderBean.

Nothing still hinders you to inject Configuration to SenderBean also if there is use for that.

Question:

Here is my singleton class:

import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.Singleton;


@Singleton
public class TestSingletons implements TestSingletonsRemote{

    @Lock(LockType.READ)
    @Override
    public void foo(int id) {
        bar(id);
    }


    private void bar(int id){
        // do stuff
    }

}

The method foo has a LockType.READ, so it can be accessed concurrently. foo actually does nothing but calls a private method of the class bar which is not annotated, so by default It should have a LockType.WRITE lock mode.

The question, as you might guess from the above scenario, is: Will the call to foo be practically concurrent?


Answer:

Your bar method is private, it's not a business method.

Default LockType.WRITE is only applicable for business methods.

Question:

I want to get the caller principal in an singleton from the logged in user. the user is authenticating against the rest service with username/password

the security domain is in the jboss-web.xml in the war

<security-domain>application-security</security-domain>

The endpoint in the war is:

@Path("/message/{message}")
public class MyRessource
{  
   @EJB
   MySingleton singletonBean;

   @GET
   public Response resource(@PathParam("message") String message)
   {        
        singletonBean.printText(message);
        System.out.println("called from: " + ctx.getUserPrincipal().getName());
}

the singleton is in an own project, and is provided as dependency at the war.

@Stateless
public class MySingletonBean implements MySingleton
{

    @Resource
    EJBContext context;

    @Resource
    SessionContext ctx;

  public void printText(String text) {
      System.out.println(text + ":: EJBContext: " + context.getCallerPrincipal().getName() + "  SessionContext: " + ctx.getCallerPrincipal().getName());      
  }

}

my web.xml:

<web-app>
    <security-role>
        <role-name>Admin</role-name>
    </security-role>

    <security-constraint>
        <web-resource-collection>
            <url-pattern>/*</url-pattern>
            <http-method-omission>OPTIONS</http-method-omission>
        </web-resource-collection>
        <auth-constraint>
            <role-name>Admin</role-name>
        </auth-constraint>
    </security-constraint>
    <login-config>
        <auth-method>BASIC</auth-method>
    </login-config>
</web-app>

standalone-full-ha.xml

<subsystem xmlns="urn:wildfly:elytron:5.0" ...>
   [...]
   <security-domain name="application-security" default-realm="application-properties" permission-mapper="default-permission-mapper">
      <realm name="application-properties"/>
   </security-domain>
   [...]
</subsystem>
   [...]

<http-authentication-factory name="application-security-http" security-domain="application-security" http-server-mechanism-factory="global">
   <mechanism-configuration>
      <mechanism mechanism-name="BASIC"/>
   </mechanism-configuration>
</http-authentication-factory>
[...]

<security-domains>
   <security-domain name="application-security" default-realm="application-properties" permission-mapper="default-permission-mapper">
      <realm name="application-properties"/>
    </security-domain>
   [...]
</security-domains>
[...]

<subsystem xmlns="urn:jboss:domain:security:2.0">
   <security-domains>
      <security-domain name="application-security">
         <authentication>
            <login-module code="UsersRoles" flag="required">
               <module-option name="usersProperties" value="file://${jboss.server.config.dir}/context-users.properties"/>
                <module-option name="rolesProperties" value="file://${jboss.server.config.dir}/context-roles.properties"/>
             </login-module>
          </authentication>
     </security-domain>
     [...]
</subsystem>
[...]

<subsystem xmlns="urn:boss:domain:undertow"...>
    <application-security-domains>
        <application-security-domain name="application-security" http-authentication-factory="application-security-http"/>
    </application-security-domains>
    [...]
</subsystem>

But i always get anonymous as principals.

What did i do wrong?


Answer:

You have at least three problems here:

  1. <subsystem xmlns="urn:jboss:domain:security:2.0"> is a legacy configuration element that does not link up with elytron;

  2. You are completely missing the ejb3 security configuration;

  3. Your EJB method is not protected with @RolesAllowed(...).

I got a similar example working:

  1. Create an elytron properties realm:

    /subsystem=elytron/properties-realm=DemoPropsRealm:add(groups-attribute=groups,\
       groups-properties={\
         path=demo-roles.properties,relative-to=jboss.server.config.dir},\
       users-properties={\
         path=demo-users.properties,relative-to=jboss.server.config.dir,plain-text=true})
    
  2. Create an elytron security domain:

    /subsystem=elytron/security-domain=DemoDomain:add(\
       realms=[{realm=DemoPropsRealm,role-decoder=groups-to-roles}],\
       default-realm=DemoPropsRealm,permission-mapper=default-permission-mapper)
    
  3. Create an elytron http-authentication factory that is mapped to our DemoDomain:

    /subsystem=elytron/http-authentication-factory=demo-http-auth:add(\
       http-server-mechanism-factory=global,\
       security-domain=DemoDomain,\
       mechanism-configurations=[{\
         mechanism-name=BASIC,\
         mechanism-realm-configurations=[{\
           realm-name=DemoApplicationDomain\
         }]\
       }])
    
  4. Map an ejb3 subsystem application security domain to our DemoDomain

    /subsystem=ejb3/application-security-domain=\
        DemoApplicationDomain:add(security-domain=DemoDomain)
    
  5. Link an undertow subsystem application security domain to our http-authentication-factory:

    /subsystem=undertow/application-security-domain=\
        DemoApplicationDomain:add(http-authentication-factory=demo-http-auth)
    

    "DemoApplicationDomain" will be the realm name in the login-config element of the web.xml and the security-domain in the jboss-web.xml file.

  6. Declare the permitted roles on your EJB method:

    @RolesAllowed("Admin")
    public void printText(String text) {
        System.out.println(text + ":: EJBContext: " + context.getCallerPrincipal().getName()
         + "  SessionContext: " + ctx.getCallerPrincipal().getName());      
    }
    

Example source is in GitHub at jax-rs-basic-auth.

Question:

I have several questions regarding the use of Singleton Bean.

First let me describe the situation. There's a web-application that will have many clients sending and receiving data to/from it. Some of this data must be persisted in database, but I need most of it to be available on the server for quick access and to take the strain off database.

I'm going to use Singleton Bean for that shared space and here are my questions:

  1. If client_1 tries to update his data in singleton member that is currently LOCKED by client_2 writing to it, what exactly happens to client_1 data? Do Ineed to prepere for such case, or is it like a stack and his write operation will take place after client_2 finished his?

  2. If I use hashmap, which keys will correspond to individual writing clients, would it be safe to place a @Lock(READ) on a set method which can only update existing records and not add new ones. The way I see it, since every client could only write to his own record there's no need to block others from updating their own records at the same time.


Answer:

  1. client_1 will wait to client_2 complete then itself update the data

  2. hashmap is not thread safe you might also be interested in to take a look one of below:

   private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
>       
>       private final Lock readLock = readWriteLock.readLock();
>     
>       private final Lock writeLock = readWriteLock.writeLock();
>     
>       private final List<E> list = new ArrayList<>();
>       
>       public void set(E o)
>       {
>           writeLock.lock();
>           try
>           {
>               list.add(o);
>               System.out.println("Adding element by thread"+Thread.currentThread().getName());
>               }
>           finally
>           {
>               writeLock.unlock();
>           }
>       }

Question:

I'm developing a web app using Java EE 6 and Shiro for REST backend and this is accessed via an Angular based frontend.

Session creation is disabled in shiro (noSessionCreation in shiro.ini) and I'm authenticating the user on every request based on a token he/she received after he/she provided the credentials for login.

In the custom Authenticating filter I'm calling

SecurityUtils.getSubject().login(bearerToken);

That calls the custom authentication realm and does the validation of the credentials.

I have a Dao where I want to use the ID of the user which is stored in the Shiro Subject's principal information.

final UserInfo userInfo = (UserInfo) SecurityUtils.getSubject().getPrincipal();
final Long currentUserId = userInfo.getId();

The Dao itself is a @Singleton EJB

@Singleton
public class TaskDao {
    ...
    public List<Task> filterActiveTasks() {
    }
}

In this case I want to filter the active tasks that belong to the user that's accessing the service.

My question and concern at the same time:

Is this thread safe? Isn't it possible that upon concurrent usage the subjects might get mixed up?

If so, how could it be avoided?

EDIT:

My concern is not just for the activeTasks but also apply for any @Singleton annotated classes where I want to use the SecurityUtils.getSubject() static method.

public List<SomeData> getSomeDataRelatedToCurrentlyLoggedInUser() {
    // Since the following is a static call in a singleton, how can I be sure
    // that when 10 users are calling this at the same time, each call will get
    // the appropriate UserInfo that was "logged-in" at the AuthenticatingFilter level
    final UserInfo userInfo = (UserInfo) SecurityUtils.getSubject().getPrincipal();
    Long currentUserId = userInfo.getId();

    return em.createNamedQuery("select s from SomeData s where s.userId = :userId").
        setParameter("userId", currentUserId).
        getResultList();

}

The login part is done in the custom AuthenticatingFilter which is -AFAIK- created for each user.

So the question still remains: Will the calls for SecurityUtils.getSubject() return the proper user or is it possible to mix them up? How can I retrieve the threadcontext in the singletons the user was bound to upon executing the login mechanism?


Answer:

You could simply introduce a ThreadLocal variable in your singleton ejb.

This way you put only stuff related to the current thread/user in the variable. For example:

@Singleton
public class TaskDao {

    private static ThreadLocal<Set<ActiveTasks>> tasksThreadLocal = new ThreadLocal<>(){
        @Override
        protected Set<ActiveTasks> initialValue() {
            return new HashSet<>();
        }
    };

    filterActiveTasks() {
         Set<ActiveTasks> tasks = tasksThreadLocal.get();
         //work with the Set
    }
}

This way the set is local to each thread and no multi-threading issues can arise.

As for SecurityUtils.getSubject(), this method uses the same mechanism internally, so it always only returns the user on the current thread, thus the user that is logged into the current request. It uses the class ThreadContext which uses a ThreadLocal to store the current user/login session.

If you somehow want access to that object (which in most cases, you don't) it has a bunch of static public methods you can call directly to set/get stuff like the subject or the security manager for the current thread.

Question:

I have Singleton enterprise bean, which starts immediately after deploy. I packed EJB into jar and want to distribute it. I set several fields of Singleton like private final String initParam = "value";. How can I expose those init parameters to administrator who will be deploy my jar onto his own GlassFish server?


Answer:

You can use Environment Entries, these should fit your needs.

Such parameters must be described in ejb-jar.xml:

<enterprise-beans>
    <session>
        <ejb-name>YourBean</ejb-name>
        <env-entry>
            <description>Your description</description>
            <env-entry-name>yourParam</env-entry-name>
            <env-entry-type>java.lang.String</env-entry-type>
            <env-entry-value>defaultValue</env-entry-value>
        </env-entry>
    </session>
</enterprise-beans>

The value of the env-entry could be injected into your bean like below:

@Resource(name = "yourParam")
private String initParam;

Env-entries could be modifed from the console of your container, normally it is a more convenient way for admins, comparing to property file modification or creating JVM parameters.

Here is some doc from Oracle: http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/env_entry/env_entry.html