2 Replies Latest reply on Feb 26, 2010 5:15 PM by pbrewer_uk

    Seam's MailSession is not Thread safe

    pbrewer_uk
      I'm using Seam 2.2.0.GA to render emails in a method annotated with @Asynchronous:

      @Asynchronous
      public void sendEmail(String template) {
        Renderer.getInstance().render(template) ;
      }

      However if this method is first called twice in quick succession, it is possible to get an error on line 64 of MailSession:
          @Unwrap
          public Session getSession() throws NamingException
          {
              if (session == null)
              {
                  // This simulates an EVENT scope component
                  return (Session) Naming.getInitialContext().lookup(getSessionJndiName()); // LINE 64
              }
              else
              {
                  return session;
              }
          }

      This is because the mailSession is APPLICATION scoped and available in the context prior to @Create method completing the initialisation of the session instance variable. I've tried adding startup=true in components.xml (to force the @Create method to complete before anything starts to send emails) but it seems to be ignoring that attribute:

      <mail:session host="myMailServer" startup="true" />

      So I guess I'll need to subclass it so force the session to be created before @unwrap can return a session (using a synchronized code block).

      Does anyone have any suggestions as to:

      1. Can I do anything (simple) to make the seam mailSession component thread safe?
      2. Should I raise a JIRA for this?
      3. Why is the startup attribute being ignored?
      4. Is it permitted to use synchronized blocks in this component (given that its use will be in a J5EE environment)?

      Any help or suggestions would be gratefully received,

      Many thanks, Pete.
        • 1. Re: Seam's MailSession is not Thread safe
          pbrewer_uk

          Following up, this is actually a more generic issue (have observed this occurring on the FaceletsCompiler component and potentially others), effecting Application scoped components that use @Create.


          Consider the following case:



          @Name("myWrapper")
          @Scope(APPLICATION)
          public class MyWrapper {
          
            private Object wrappedObject ;
          
            @Create
            public void setupWrappedObject() {
              // code to setup the wrappedObject
              ...
              this.wrappedObject = aValue ;
            }
          
            @Unwrap
            public Object getWrappedObject() {
              return this.wrappedObject ;
            }
          
          
          }



          And then consider how Seam creates the instance when it is referenced (extract from Component.java)...


          public Object newInstance()
             {
                if (log.isTraceEnabled()) {
                   log.trace("instantiating Seam component: " + name);
                }
          
                Object instance;
                try{
                   instance = instantiate();
                    
                   if (getScope()!=STATELESS) {
                      //put it in the context _before_ calling postconstuct or create
                      getScope().getContext().set(name, instance);
                   }
                   
                   postConstruct(instance);
                      
                   if (getScope()!=STATELESS) {
                      callCreateMethod(instance);
                      
                      if (Events.exists()) {
                          Events.instance().raiseEvent("org.jboss.seam.postCreate." + name, instance);
                      }
                   }
                   
                } catch (Exception e) {
                     if (getScope()!=STATELESS) {
                          getScope().getContext().remove(name); 
                     }
          
                     throw new InstantiationException("Could not instantiate Seam component: " + name, e);
                }
          
                return instance;
             }



          In a multi-threaded environment, setting the variable in the context prior to running @Create means that other components may access the @Unwrap method prior to the @Create method completing. From the seam code comment put it in the context before calling postconstuct or create I assume this is done deliberately. But I don't understand why it is done like that - anyone know why?


          Assuming the Component.java is correct then it means @Create can't safely be used in Application-scoped components (or indeed any other cotext that has multi-thread access).


          Can any of the seam team comment on this?


          Thanks in advance, Pete.

          • 2. Re: Seam's MailSession is not Thread safe
            pbrewer_uk

            This also applies to QueueConnection too.


            Can anyone comment on this behaviour - shall I raise a JIRA for this behaviour?


            Thanks, Pete.