4 Replies Latest reply on Aug 7, 2007 9:43 AM by Jens Weintraut

    @PersistenceContext in a SFSB created by a factory

    Jens Weintraut Apprentice

      Hi there,

      is it possible to have a PersistenceContext in a bean (don't really know which type it is, sorry, I'm a noob somedays :D) which is created by a factory?

      The thing I want to do is to imlpement the possibility to switch the implementation of an interface. This works. In one of these implementations I want to obtain the PersistenceContext and that doesn't work.

      But let me show you some code:

      @Name("upDownloadFactory")
      @Scope(ScopeType.APPLICATION)
      @Startup
      public class UpDownloadFactory implements Serializable {
       private String className;
      
       @Out(required=false)
       private UpDownload upDownload;
      
       @Factory(value="upDownload", scope=ScopeType.SESSION, autoCreate=true)
       public UpDownload getUpDownload() {
       if(upDownload == null) {
       try {
       if(className == null || className.equals("")) {
       className = "com.idsscheer.ares.sessions.UpDownloadDatabase";
       }
       upDownload = (UpDownload) Class.forName(className).newInstance();
       ... and so on ...
       }
      
       return upDownload;
       }
      
       public void setClassName(String className) {
       this.className = className;
       }
      }

      This is the factory I wrote. As you can see the implementation has to be set in components.xml and sets the className property. All those parameters I set in the @Factory annotation shall setup the "upDownload" as SFSB.

      Here is one implementation of the managed bean:
      @Scope(ScopeType.SESSION)
      @Stateful
      public class UpDownloadDatabase implements UpDownload, Serializable {
       @PersistenceContext(unitName = "aresDatabase")
       private transient EntityManager em;
      
       public boolean upload(UpDownloadFileinfo fileInfo) {
       ... do the upload with em ...
       }
      
       public List<UpDownloadFileinfo> getAttachedFiles(long testactionID) {
       ... show a list of attached files ...
       }
      
       @Remove @Destroy
       public void destroy() {
       }
      }


      In this implementation the EntityManager is needed but on invokation of this bean the console tells me that
      Caused by: java.lang.IllegalArgumentException: @PersistenceContext may only be used on session bean or message driven bean components: upDownload
       at org.jboss.seam.Component.initMembers(Component.java:663)
       at org.jboss.seam.Component.<init>(Component.java:253)
       at org.jboss.seam.Component.<init>(Component.java:203)
       at org.jboss.seam.init.Initialization.addComponent(Initialization.java:851)
       ... 93 more


      Has anybody an idea how to implement such a factory?

      Thanks in advance
      Newlukai

        • 1. Re: @PersistenceContext in a SFSB created by a factory
          Pete Muir Master

          For Seam injection to work you have to instantiate the component through Seam e.g. Component.getInstance(). If you make the UpDownloadDatabase a Seam component then this is all you need to do.

          If you want it as a non-seam SFSB, you need to ask EJB3 to instantiate it for you (e.g. JNDI lookup, @EJB).

          • 2. Re: @PersistenceContext in a SFSB created by a factory
            Jens Weintraut Apprentice

            So I have to change the @Factory method to

            upDownload = Component.getInstance("upDownload");

            ? But, the component "upDownload" isn't yet instantiated, so Seam would look up for "upDownload" and since the @Name is missing on UpDownloadDatabase it would just find the @Factory in UpDownloadFactory. I'm sure I've accidentally ignored something but for me it looks like this would be a recursive call, isn't it?

            On the other side, when I call Component.getInstance() it isn't possible to switch the implementation via components.xml anymore?!?

            A workaround would be sth like this:

            @Name("upDownloadFactory")
            @Scope(ScopeType.APPLICATION)
            @Startup
            public class UpDownloadFactory implements Serializable {
             private String className;
            
             @Out(required=false)
             private UpDownload upDownload;
            
             @Factory(value="upDownload", scope=ScopeType.SESSION, autoCreate=true)
             public UpDownload getUpDownload() {
             if(upDownload == null) {
             try {
             if(className == null || className.equals("")) {
             className = "Database";
             }
             upDownload = (UpDownload) Component.getInstance("upDownload"+className);
             ... and so on ...
             }
            
             return upDownload;
             }
            
             public void setClassName(String className) {
             this.className = className;
             }
            }


            @Scope(ScopeType.SESSION)
            @Stateful
            @Name("upDownloadDatabase")
            public class UpDownloadDatabase implements UpDownload, Serializable {
             @PersistenceContext(unitName = "aresDatabase")
             private transient EntityManager em;
            
             public boolean upload(UpDownloadFileinfo fileInfo) {
             ... do the upload with em ...
             }
            
             public List<UpDownloadFileinfo> getAttachedFiles(long testactionID) {
             ... show a list of attached files ...
             }
            
             @Remove @Destroy
             public void destroy() {
             }
            }



            @Scope(ScopeType.SESSION)
            @Stateful
            @Name("upDownloadFilesystem")
            public class UpDownloadFilesystem implements UpDownload, Serializable {
             public boolean upload(UpDownloadFileinfo fileInfo) {
             ... do the upload with em ...
             }
            
             public List<UpDownloadFileinfo> getAttachedFiles(long testactionID) {
             ... show a list of attached files ...
             }
            
             @Remove @Destroy
             public void destroy() {
             }
            }


            Would that be possible?

            • 3. Re: @PersistenceContext in a SFSB created by a factory
              Pete Muir Master

               

              "Newlukai" wrote:
              So I have to change the @Factory method to
              upDownload = Component.getInstance("upDownload");

              ? But, the component "upDownload" isn't yet instantiated, so Seam would look up for "upDownload" and since the @Name is missing on UpDownloadDatabase it would just find the @Factory in UpDownloadFactory. I'm sure I've accidentally ignored something but for me it looks like this would be a recursive call, isn't it?


              Yes. Your desgin has flaws.

              If all you want to do is switch out the implementation from components.xml then you can just.

              <component name="upDownload" class="UpDownloadDatabase" />
              <!--<component name="upDownload" class="UpDownloadFileSystem" />-->


              and miss out the @Name annotations on the class. You don't need your factory.

              • 4. Re: @PersistenceContext in a SFSB created by a factory
                Jens Weintraut Apprentice

                OK. I changed this. I'm wondering why I didn't do that before ...

                And yap, it works now ;)

                Now I'm running into another problem I've to figure out. You don't know why an uninvolved Seam component turns to null as soon as I click on upload on a ice:inputFile?