6 Replies Latest reply on May 28, 2009 6:13 PM by Israel Fonseca

    Executing a Method when Seam Starts

    Israel Fonseca Apprentice
      I want to trigger a EJB timer in my Seam component (it have to send emails at every X minutes), so i'm trying to execute-it with the Seam @Install annotation + @Create, but it's not working.

      How could i do that?

      Thks
        • 1. Re: Executing a Method when Seam Starts
          Israel Fonseca Apprentice

          @Startup solved my problem but now there is another. How can i retrive my timer, or delete all timers when the application starts? It keep creating timers, and i want to manage them (delete-them).  I need that my timers live just for the scope of my application (if the server restart, it's make sense to my service just be restarted too with the application).


          This timer stuff is cool, but very crazy.

          • 2. Re: Executing a Method when Seam Starts
            Arbi Sookazian Master

            This may help.  We have some custom JARs, so ignore the AD lookup API stuff (e.g. UserItem).  This solution uses org.jboss.seam.postInitialization rather than @Startup but most likely same effect/strategy.


            AFAIK, you only want one EJB timer to exist, so why are there multiple?  you should not have to deal with deleting them.


            In my case below, the scheduleTimer() method in the controller component should be called once per start of app server, no more, no less.


            I'm not sure if/how the EJB timers are persisted to a DB, but at the time I believe I was using HSQLDB.


            Read JSR220-core ch. 18 on timer service for more info...


            components.xml:


            <event type="org.jboss.seam.postInitialization">   
                    <action execute="#{controller.scheduleTimer}"/>
               </event>
               
               <!-- Install the QuartzDispatcher -->
               <async:quartz-dispatcher/>   
              
               <!-- Install the EJB timer service -->  
               <!-- <async:timer-service-dispatcher />  -->



            ScheduleProcessor.java:


            @Name("processor")
            @AutoCreate
            @Scope(ScopeType.APPLICATION)
            public class ScheduleProcessor { 
                
                 //TO DO: map needs to be stored in application context as it is session-independent data
                 //TO DO: convert this into an ArrayList of map objects b/c we will need a map
                 // for every drop-down in each app
                
                private List<UserItem> userItemList;
                
                private Map<String, List<UserItem>> map;
                
                @Logger Log log;
                
                //@In(create=true) TimerService timerService;
                
                //EJB Timer version...
                @Asynchronous
                @Transactional
                public Timer createEjbTimer(@Expiration Date when, @IntervalDuration Long interval, String distinguishedGroupName) 
                {            
                     process(when, interval, distinguishedGroupName);
                     
                     return null;
                }
                
                //Quartz version...
                @Asynchronous
                @Transactional
                public QuartzTriggerHandle createQuartzTimer(@Expiration Date when, @IntervalDuration Long interval, String distinguishedGroupName)
                {
                     process(when, interval, distinguishedGroupName);
                     
                     return null;
                }
                
                private void process(Date when, Long interval, String distinguishedGroupName) {
                               
                      log.info("when = " + when);
                      log.info("interval = " + interval);
                      log.info("distinguishedGroupName = "+distinguishedGroupName);
                      
                      String searchBase = CoxProperties.getPropertyObject().getProperty(CoxConstants.ACTIVE_DIRECTORY_SEARCH_BASE);
                     String providerUrl = CoxProperties.getPropertyObject().getProperty(CoxConstants.ACTIVE_DIRECTORY_PROVIDER_URL);
                     String principal = CoxProperties.getPropertyObject().getProperty(CoxConstants.ACTIVE_DIRECTORY_USER);
                     String credentials = CoxProperties.getPropertyObject().getProperty(CoxConstants.ACTIVE_DIRECTORY_PWD);
                 
                     // Declare holders search result's
                     SearchAdapterResult<UserItem> userSearchResults = null;        
                     
                     // Create a new instance of CADILS search adapter
                     SearchAdapter sa = new SearchAdapter(searchBase, providerUrl, principal, credentials);
                 
                     try {
                           String groupSearchFilter = "*)(memberOf=" + distinguishedGroupName;   
                           userSearchResults = sa.searchBySAMAccountName(groupSearchFilter);
                 
                           if (userSearchResults.hasItems()) {
                               //List of all the AD users who belong to your group
                                userItemList = userSearchResults.getItemList();
                                if (map == null) {
                                     map = new TreeMap<String, List<UserItem>>();
                                }
                                map.put(distinguishedGroupName, userItemList);
                           }
                     } 
                     catch (SearchFailedException sfe) {
                           log.error(sfe);
                     }
                     
                }
                
                
                public Map<String, List<UserItem>> getMap() {
                     return map;
                }
            }



            ScheduleController.java:


            @Name("controller")
            @AutoCreate
            public class ScheduleController implements Serializable { 
               
                @In ScheduleProcessor processor;    
                @Logger Log log;        
                 private Map<String,List<UserItem>> map;     
                 private String distinguishedNameShims;     
                 private String distinguishedNameItJava;     
                 private Timer timer;     
                 private QuartzTriggerHandle quartzTriggerHandle;
                 
                public void scheduleTimer()
                {                           
                     Long pollingInterval = null;
                              
                      String activeDirectoryPollingInterval = CoxProperties.getPropertyObject().getProperty(CoxConstants.ACTIVE_DIRECTORY_POLLING_INTERVAL);
                      if (activeDirectoryPollingInterval != null) {
                           pollingInterval = Long.valueOf(activeDirectoryPollingInterval);
                      }
                      
                      Boolean usingEjbTimer = Boolean.valueOf(CoxProperties.getPropertyObject().getProperty(CoxConstants.USING_EJB_TIMER)==null?"false":CoxProperties.getPropertyObject().getProperty(CoxConstants.USING_EJB_TIMER));          
                      distinguishedNameShims = CoxProperties.getPropertyObject().getProperty(CoxConstants.DISTINGUISHED_NAME_SHIMS);               
                                
                      if (usingEjbTimer) {                         
                           timer = processor.createEjbTimer(new Date(), pollingInterval, distinguishedNameShims);
                      }
                      else {
                           quartzTriggerHandle = processor.createQuartzTimer(new Date(), pollingInterval, distinguishedNameShims);
                      }
                    
                }
                            
                
                public Map<String, List<UserItem>> getMembersOfRoleMap(){
                     
                     //get the map from the application context of EJBPollingProcessorBean             
                     map = processor.getMap();
                              
                     return map;
                }
                     
                 
            }


             

            • 3. Re: Executing a Method when Seam Starts
              Israel Fonseca Apprentice

              I just want one timer indeed, but i create one every time that my app starts, so if i dont delete the old ones when my app start, i will be making new timers (timers are persistent), that's why i'm deleting them every time my app starts.


              hmm, but i should just dont create new ones istead deleting the old. D'oh.


              Anyway, Arbi dont you get EJB error when restarting your app? Lets say that your timer execute something every minute, so if you shutdown the server for 10 minutes, when you restart it, the timer will try to re-execute the timers 10 times, but in that moment the Seam application did not started yet, so I get an error telling that a seam component (logger) was tried to be executed outside the Seam context.


              Did you understand?


              Thks in advance.

              • 4. Re: Executing a Method when Seam Starts
                Arbi Sookazian Master

                What are you using as a back-end to persist your timers (e.g. RDBMS or what?)


                Like I said, IIRC I was using HSQLDB which is an in-process DB.  AFAIK, when you shut down JBoss and are using HSQLDB, the records are gone.


                Perhaps there is a way in the API to determine if there is already a timer existing?  Have you tried Quartz?  Sorry, the code I used to periodically query AD and I haven't used EJB timers in any other context other than that.


                I believe there are some improvements to EJB timer service in EJB 3.1...

                • 5. Re: Executing a Method when Seam Starts
                  Nikolay Elenkov Master

                  Have a look at the javax.ejb.TimerService interface. You can list existing timers and cancel the ones you don't need.
                  Or you can simply choose to reuse the one already installed, if settings haven't changed.


                  Quartz gives you more control over this, but for your use case you may not need it.
                  You could also tweak the JBoss Timer service if you want. Have a look at scheduler-service.xml
                  in your JBoss deploy directory.


                  HTH


                  • 6. Re: Executing a Method when Seam Starts
                    Israel Fonseca Apprentice

                    I got the things working now. I just check for older timers, and dont add new ones. Anyway, the only annoyng thing is the exception on jboss startup, but nothing serious.


                    And at least in the Jboss 4.2.3, the timer is persistent Arbi. In fact that's what the specification says about EJB Timers, they are that way by default. I'm a jboss-as noob, but i think that the JBoss save them in an local-file with the HSQLDB.


                    And i'm trying to just use EJB, i dont want third partie stuff. :)


                    And thks for the xml tip Nikolay.


                    Israel