TImerService

I am in the process developing a small framwork which hopefully will enable me to list a suite of scheduled beans using TimerService in EJB3. However I consequently fail on getting an instance of the TimerService. I am running a SetUp using Jboss 7.1.1.final, with vaadin 7. And I have a small class which is supposed to just, quite simply, list the TImers currently active. In other frameworks I would have done the following;


/**
 * 
 */
package se.point.unity.unitygui.jobmanager;

import javax.annotation.Resource;
import javax.ejb.Singleton;
import javax.ejb.TimerService;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import se.point.unity.unitygui.global.GlobalData;

/**
 * @author Joakim Hansson
 *
 */
@Singleton
public class TimerList
{
  @Resource
  TimerService timerService;
  
  private static Logger logger = LoggerFactory.getLogger (TimerList.class);
  public TimerList ()
  {
    logger.debug ("------------------------------------------- TimerService loop!");
    if (timerService != null)
    {
      for (Object o:timerService.getTimers())
      {
        logger.debug ("Looping the loop!");
      }
    }
    logger.debug ("Leaving!");
  }
}

I would expect the CDI mechanism to fill the TimerService Instance used by the current EJB container. Not so using vaadin. So, I resort to try to fish up the Timerservice using the standard JNDI name and location; i.e.:


private static void createTimerService ()
	{
	  try {
	    timerService = (TimerService) new InitialContext().lookup("java:comp/TimerService");
	  } catch (NamingException e) {
	    e.printStackTrace();
	    timerService = null;
	  }
	}

No dice. I get a null pointer exception caught in trhe NamingException catch clause.

Any ideas out there? I simply would like to get a handle on the available classes? It should be doable, shouldn’t it? Or is it me that miss something here?

Timer server works for me. At least it works if I reference it from one of the Beans that has a scheduled task…

Server: GlassFish 3.1.2.2


@Singleton(name = "MyTimerBean")
@TransactionManagement(TransactionManagementType.CONTAINER)
@javax.ejb.ConcurrencyManagement(javax.ejb.ConcurrencyManagementType.CONTAINER)
@javax.ejb.Lock(LockType.READ)
public class MyTimerBean implements java.io.Serializable {

    private static final long MAX_POLL_TIME_IN_MILLIS = 15 * 60 * 1000; // 15 Minutes
    private static final String POLL_TIMER_INFO = "MyTimerBean.checkForPollNotifications";

    /**
     * A reference to the containers javax.ejb.TimerService
     */
    @Resource
    private transient javax.ejb.TimerService timerService;


    public boolean isScheduledTimerActive() {
        for (javax.ejb.Timer timer : timerService.getTimers()) {
            final long currentTimeMillis = System.currentTimeMillis();
            final long millisToNextSchedule = timer.getNextTimeout().getTime() - currentTimeMillis;
            if (LOGGER.isLoggable(Level.FINE)) {
                LOGGER.log(Level.FINE, "MyTimerBean.isScheduledTimerActive() - Info:{0} isCal:{1} isPersist:{2} Next:{3}", 
                                new Object[]{timer.getInfo(), timer.isCalendarTimer(), timer.isPersistent(), millisToNextSchedule});
            }
            if (POLL_TIMER_INFO.equals(timer.getInfo()) && timer.isCalendarTimer() && timer.isPersistent() 
                                && (millisToNextSchedule > 0) && (millisToNextSchedule < MAX_POLL_TIME_IN_MILLIS)) {
                return true;
            }
        }
        LOGGER.log(Level.WARNING, "MyTimerBean.isScheduledTimerActive() - Could not find an active Timer for {0}", POLL_TIMER_INFO);
        return false;
    }


@javax.ejb.Schedule(second = "30",
                 minute = "0,5,10,15,20,25,30,35,40,45,50,55", 
                hour = "*", 
                dayOfWeek = "*", 
                dayOfMonth = "*", 
                month = "*", 
                year = "*", 
                info = POLL_TIMER_INFO)
    @javax.ejb.Lock(LockType.WRITE)
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void checkForPollNotifications() {
        ... 
    }
}

AHum, yes, My problem (and this is most likely due to a lack of understanding of some fundamental concept here), is that I aim to create a simple job manager where I can start/stop and reschedule jobs from a graphical user interface. So I do this from a simple;


public class UnityguiApplication extends UI {

which basically creates a window which is supposed to list the currently active scheduled job beans within the ear. The goal beeing that I can reschedule them, start and stop them.

My problem is that the TimerService seems to be inaccessible in this context. Actually most all type of content dependency injection seems to fail. When I try to get the entitymanager for my JPA layer it also fails (but there is a workaround using a JNDI lookup, and I found it here on the forum), it is no longer a problem, and thats why I resorted to my attempt to fish it out using a JNDI lookup (which as far as I am able to discern is a standard path to the TimerService according to the oracle documentation (I might be wrong on this). However, the name lookup seems to fail there as well, indicating failure on my part to fully understand the naming structure.SO am a bit lost here.

AFAIK your particular way of doing it actually does work, but then I create a completely separate bean (which is a part of the .ear). But when used from the vaadin application the CDI fails to materialize… Any ideas on how to fish it out via JNDI lookups? Would this addon:


        <dependency>
            <groupId>com.vaadin</groupId>
            <artifactId>vaadin-cdi</artifactId>
            <version>1.0.0.alpha1</version>
        </dependency> 

Help me with my goal?

Ok: I have done some more research and it seams like the only place where injection works is in the ui provider (i can access the inection mechanism here and then propagate it via globally accessible dataobjects). Not very nice solution… Exploring cdiutils…

Yes that addon will save you a lot of grief.

One thing you should be aware of is where you create your persistenceUnit . By default it is only visible in the Module ( where the persistence.xml resides ). So I usually create a separate jar just containing the persistence.xml and add it to my ear, this way it is visible to the entire application.

Someone please correct me if I’m wrong , but your UI wont have a JPA transaction context by default , so to get your entityManage to operate correctly you should use a UserTransaction , or you could give the Spring integration addon a try ( have not worked with it yet ).



@SuppressWarnings("serial")
@Interceptors(TransactionEnforcer.class)
@PersistenceContext(name = "persistence/Dnsrbl", unitName = "dnsrbl.StorePU")
@ViewInterface(SearchView.class)
public class SearchPresenter extends AbstractPresenter<SearchView> {

    @PersistenceContext(unitName = "com.adept.dnsrbl.StorePU")
    protected transient EntityManager eManager;

    public testEmanager() {
        Foo foo= eManager.merge(eManager.find(Foo.class,1));
    }
    
}

copied from one of
http://www.adam-bien.com/roller/abien/
blogs…


public class TransactionEnforcer {

    @Resource
    UserTransaction tx;
    private final static Logger LOGGER = Logger.getLogger(TransactionEnforcer.class.getName());

    @AroundInvoke
    public Object beginAndCommit(final InvocationContext ic) throws Exception {
        boolean isStarted;
        try {
            tx.begin();
            isStarted = true;
        } catch (javax.transaction.NotSupportedException e) {
            isStarted = false;
        }
        try {
            final Object retVal = ic.proceed();
            if (isStarted) {
                tx.commit();
            }
            return retVal;
        } catch (RollbackException e) {
            LOGGER.severe("-----------------Caught (in interceptor): " + e.getCause());
            throw e;
        } catch (RuntimeException e) {
            if (isStarted) {
                tx.rollback();
            }
            throw e;
        }

    }
}

If using Vaadin CDI add-on, check the annotations on your UI.
Using the correct @CDIUI annotation (which also implies @UIScoped) should make injections work in it when it is created by CDIUIProvider.

Hay there Henri!
I’m collaborating whis Joakim on this project, and the thing is, we are able to confirm that injection works well in the @CDIUI-annotated UI


@CDIUI("unity")
public class UnityguiApplication extends UI {

	@UIScoped
	@PersistenceContext(name = "persistence/em", unitName = "foo")
	private EntityManager entityManager;
	@UIScoped
	@Resource
	private UserTransaction userTransaction;
	@Inject
	private CDIViewProvider cdiViewProvider;
...
	@Override
	public void init(VaadinRequest request) {
		if (userTransaction == null) {
			logger.error("UserTransaction == null");
		}
		if (entityManager == null) {
			logger.error("EntityManager == null");
		}

		VerticalLayout layout = new VerticalLayout();
		layout.setSizeFull();

		Navigator navigator = new Navigator(UnityguiApplication.this, layout);
		navigator.addProvider(cdiViewProvider);

		setContent(layout);

Here this works splendid…

But in the View this failes:


@CDIView(UnityNavigator.ACCOUNT)
public class AccountManage extends VerticalLayout
		implements View{

	@PersistenceContext
	private EntityManager entityManager;
	@Resource
	private UserTransaction userTransaction;

	public AccountManage() throws Exception {
		if (userTransaction == null) {
			throw new Exception("Failed to inject UserTransaction");
		}
		if (entityManager == null) {
			throw new Exception("Failed to inject EntityManager");
		}

I made several attempts annotating the EnityManager and UserTransaction with @UIScoped and @Inject and so on in different combinations. But with no better result.

The primary error in our ways was that we were refering to injected beans in the constructor.
Appearently, it is not guaranteed that a bean is injected on construct time.
We therefore implemented a postConstruct pattern

[code]
@CDIView
public class MyClass{

@PeristenceContext
private EntityManager em;

private MyClass(){
}

@PostConstruct
private void init(){
DerpEntity derp = em.find(DerpEntity.class, 1);
}
}

[/code]This way we make sure noone implements the class the “wrong” way…

You cannot access any injected properties in your constructor, use a method annotated with @PostConstruct like jens brimberg showed.
The injection for your properties only happens after your constructor is called, Alternatively you can annotate your constructor with @Inject parameters , but I don’t know if @PersistenceContext && @Resource is valid for parameters , so @PostConstruct is you best bet…