4 Replies Latest reply on Feb 27, 2008 8:55 PM by Keith Naas

    using ServletContextListener with Seam

    System Administrator Expert

      I need to have a EJB timer scheduled/created when JBoss is started and the Seam app is deployed.  The data is stored in the application-scoped POJO processor component that queries Active Directory for user related data in a distribution group.  Goal is to minimize hits to AD.


      When I call the schedule method on the controller POJO from a button on a facelet, everything works fine (drop-down in facelet is populated properly).


      When I created a class that implements the ServletContextListener interface and added the proper metadata to the web.xml, I am getting the following stack trace when the Seam app is deployed and the contextInitialized method is exec'd.  This is happening because the processor injection object is null in the controller POJO.  I don't know why it's null when I use the IJWATServletContextListener class but it's not null when I fire the method manually from a JSF commandButton...


      11:15:15,167 ERROR [[/SecurityAuditPOC]] Exception sending context initialized event to listener instance of class com.cox.util.IJWATServletContextListener
      java.lang.NullPointerException
           at com.cox.ejb.session.EJBPollingControllerBean.scheduleTimer(EJBPollingControllerBean.java:46)
           at com.cox.util.IJWATServletContextListener.contextInitialized(IJWATServletContextListener.java:20)



      What is the best way to handle this auto-start type of functionality in a Seam app when it will affect all user sessions?


      IJWATServletContextListener.java:


      public class IJWATServletContextListener implements ServletContextListener     {
           
           public static long applicationInitialized =     0L;
      
           /* Application Startup Event */
           public void     contextInitialized(ServletContextEvent ce) {
                applicationInitialized = System.currentTimeMillis();
                System.out.println("*** in contextInitialized: currentTimeMillis = " + applicationInitialized);
                EJBPollingControllerBean test = new EJBPollingControllerBean();
                test.scheduleTimer();
           }
      
           /* Application Shutdown     Event */
           public void     contextDestroyed(ServletContextEvent ce) {}
      }



      controller POJO:


      @Name("controller")
      @AutoCreate
      public class EJBPollingControllerBean { 
         
          @In EJBPollingProcessorBean processor;
          
          @Logger Log log;
          
          private String SAMAccountName;
           
           //default DN below
           private String distinguishedName = "CN=!CCI ORG APP - SHIMS Tech,OU=Groups,OU=Orange County,OU=CCI,DC=CORP,DC=COX,DC=com";
                
           private Map<String,String> map;
           
          //test method from button in JSF
          public void scheduleTimer()
          {
               Long pollingInterval = null;
                        
                String activeDirectoryPollingInterval = CoxProperties.getPropertyObject().getProperty(CoxConstants.ACTIVE_DIRECTORY_POLLING_INTERVAL);
                if (activeDirectoryPollingInterval != null) {
                     pollingInterval = Long.valueOf(activeDirectoryPollingInterval);
                }
                
                Timer timer = processor.schedulePoller(new Date(), pollingInterval,     distinguishedName);
              
             
          }
             
          //bug found! don't call the schedulePoller method from a JSF component backing method; the JSF spec does not state how many times
          //the backing methods must/can be called (and it was being called twice and thus inserting two new timers in the TIMERS table)
          public Map<String, String> getMembersOfRoleMap(){
               //get the map from the application context of EJBPollingProcessorBean
               
               List<UserItem> userItemList = processor.getUserItemList();
               Iterator<UserItem> it = null;
               
               if (userItemList != null) {
                    it = userItemList.iterator();
               }
               
               map = new TreeMap<String, String>();
               
               while(it.hasNext()) {
                    UserItem userItem = it.next();
                    String samAccountName = userItem.getSAMAccountName();
                    String displayName = userItem.getDisplayName();
                    map.put(samAccountName, displayName);
               }
                        
               return map;
          }
          
           
           public void setDistinguishedName(String distinguishedName) {
                this.distinguishedName = distinguishedName;
           }
           
           public String getDistinguishedName() {
                return distinguishedName;
           }
           
           public String getSAMAccountName() {
                return SAMAccountName;
           }
           
           public void setSAMAccountName(String SAMAccountName) {
                this.SAMAccountName = SAMAccountName;
           }
                
           
      }



      processor POJO:


      @Name("processor")
      @AutoCreate
      @Scope(ScopeType.APPLICATION)
      public class EJBPollingProcessorBean { 
          
           //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
          
          List<UserItem> userItemList;
      
          @Logger Log log;
          
          @Asynchronous
          @Transactional
          public Timer schedulePoller(@Expiration Date when, @IntervalDuration 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();
                    }
              } 
              catch (SearchFailedException sfe) {
                    log.error(sfe);
              }
                      
              return null;
          }
              
          /*public Map<String,String> getMap() {
               return map;
          }*/
          
          public List<UserItem> getUserItemList() {
               return userItemList;
          }
      }