Search code examples
javacdibatch-processingjava-ee-7

Java EE 7 Batch API : produce job scoped CDI Bean


I'm currently working on a Java EE 7 Batch API application, and I would like the lifecycle of one of my CDI Bean be related to the current job. Actually I would like this bean to have a @JobScoped scope (but it doesn't exist in the API). Also I would like this bean to be injectable in any of my jobs class.

At first, I wanted to create my own @JobScoped scope, with a JobScopedContext, etc. But then I came with the idea that Batch API has the JobContext bean with a unique job id per bean.

So I wonder if I could manage the lifecycle of my job scoped bean with this JobContext.

For example, I would have my bean that I want to be job scoped :

@Alternative
public class JobScopedBean
{
   private String m_value;

   public String getValue()
   {
      return m_value;
   }

   public void setValue(String p_value)
   {
      m_value = p_value;
   }
}

Then I would have the producer of this bean which will return the JobScopedBean associated to the current job (thanks to the JobContext which is unique per job)

public class ProducerJobScopedBean
{

  @Inject
  private JobContext m_jobContext;// this is the JobContext of Batch API

  @Inject
  private JobScopedManager m_manager;

  @Produces
  public JobScopedBean getObjectJobScoped() throws Exception
  {
      if (null == m_jobContext)
     {
         throw new Exception("Job Context not active");
      }

      return m_manager.get(m_jobContext.getExecutionId());
   }
}

And the manager which holds the map of my JobScopedBean :

@ApplicationScoped
public class JobScopedManager
{
   private final ConcurrentMap<Long, JobScopedBean> mapObjets = new   ConcurrentHashMap<Long, JobScopedBean>();

   public JobScopedBean get(final long jobId)
   {
      JobScopedBean returnObject = mapObjets.get(jobId);
      if (null == returnObject)
      {
         final JobScopedBean ajout = new JobScopedBean();
         returnObject = mapObjets.putIfAbsent(jobId, ajout);

         if (null == returnObject)
         {
            returnObject = ajout;
         }
      }
      return returnObject;
   }

Of course, I will manage the destruction of the JobScopedBean at the end of each job (through a JobListener and a CDI Event).

Can you tell me if I'm wrong with this solution?

It looks correct to me but maybe I'm missing something?

May be there is a better way to handle this?

Thanks.


Solution

  • So it boils down to creating @Dependent scoped beans that are based on a job on creation. Works fine for beans with a lifespan shorter than the job, so for the standard scopes only @Dependent (@Request/@Session/@Converstion might be ok but do not apply here).

    It will cause problems for other Scopes, especially @ApplicationScoped/@Singleton. If you inject the JobScopedBean into one of them. You might be (un)lucky to have an active Job when you need them the first time, but the beans will always be attached to that initial job (@Dependent scope beans are not pseudoscoped so will not create proxies to get the contextual instance)

    If you want something like that, create a customscope.