1 2 Previous Next 21 Replies Latest reply on Dec 9, 2009 2:53 PM by pmuir

    Enabling an interceptor in a library

      I am trying to create a simple .jar file which could be included in a web application, containing a number of CDI utilities, such as logging interceptors, a set of handy stereotypes, etc., but I am hitting an unexpected problem when attempting to enable the interceptors... namely, it appears that I need to define all of my interceptors in one location -- either in the beans.xml from the .jar library file, or in the beans.xml from the web app, but I am not permitted to define a list of interceptors in both locations, even if I have no duplication of actual interceptors... for example, if I have the following beans.xml in my library:


      <beans>
          <interceptors>
              <class>com.users.log.LoggingInterceptor</class>
          </interceptors>
      </beans>



      and the following beans.xml in my web application:


      <beans>
          <interceptors>
              <class>com.users.security.SecurityInterceptor</class>
          </interceptors>
      </beans>



      I get the following exception upon loading Glassfish (build 74, which is the latest at the time of writing):




      SEVERE: Exception while loading the app
      org.glassfish.deployment.common.DeploymentException: <interceptor> can only be specified once, but it is specified muliple times [File: file:/C:/Documents and Settings/Matt/My Documents/NetBeansProjects/UserManagement/target/UserManagement/WEB-INF/beans.xml; Node: [interceptors: null], File: file:/C:/Program Files/glassfish-v3-b74/glassfishv3/glassfish/domains/domain1/generated/jsp/com.user_UserManagement_war_1.0-SNAPSHOT/loader_5889032/META-INF/beans.xml; Node: [interceptors: null], File: file:/C:/Program Files/glassfish-v3-b74/glassfishv3/glassfish/domains/domain1/generated/jsp/com.user_UserManagement_war_1.0-SNAPSHOT/loader_5889032/META-INF/beans.xml; Node: [interceptors: null]]
              at org.glassfish.weld.WeldDeployer.event(WeldDeployer.java:155)
              at org.glassfish.kernel.event.EventsImpl.send(EventsImpl.java:125)
              at org.glassfish.internal.data.ApplicationInfo.load(ApplicationInfo.java:224)
              at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:338)
              at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:183)
              at org.glassfish.deployment.admin.DeployCommand.execute(DeployCommand.java:272)
              at com.sun.enterprise.v3.admin.CommandRunnerImpl$1.execute(CommandRunnerImpl.java:305)
              at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:320)
              at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1176)
              at com.sun.enterprise.v3.admin.CommandRunnerImpl.access$900(CommandRunnerImpl.java:83)
              at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1235)
              at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1224)
              at com.sun.enterprise.v3.admin.AdminAdapter.doCommand(AdminAdapter.java:365)
              at com.sun.enterprise.v3.admin.AdminAdapter.service(AdminAdapter.java:204)
              at com.sun.grizzly.tcp.http11.GrizzlyAdapter.service(GrizzlyAdapter.java:166)
              at com.sun.enterprise.v3.server.HK2Dispatcher.dispath(HK2Dispatcher.java:100)
              at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:245)
              at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:791)
              at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:693)
              at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:954)
              at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:170)
              at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:135)
              at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:102)
              at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:88)
              at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:76)
              at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:53)
              at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:57)
              at com.sun.grizzly.ContextTask.run(ContextTask.java:69)
              at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:330)
              at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:309)
              at java.lang.Thread.run(Thread.java:619)
      Caused by: org.jboss.weld.DeploymentException: <interceptor> can only be specified once, but it is specified muliple times [File: file:/C:/Documents and Settings/Matt/My Documents/NetBeansProjects/UserManagement/target/UserManagement/WEB-INF/beans.xml; Node: [interceptors: null], File: file:/C:/Program Files/glassfish-v3-b74/glassfishv3/glassfish/domains/domain1/generated/jsp/com.user_UserManagement_war_1.0-SNAPSHOT/loader_5889032/META-INF/beans.xml; Node: [interceptors: null], File: file:/C:/Program Files/glassfish-v3-b74/glassfishv3/glassfish/domains/domain1/generated/jsp/com.user_UserManagement_war_1.0-SNAPSHOT/loader_5889032/META-INF/beans.xml; Node: [interceptors: null]]
              at org.jboss.weld.xml.BeansXmlParser.parse(BeansXmlParser.java:202)
              at org.jboss.weld.bootstrap.BeanDeployment.parseBeansXml(BeanDeployment.java:107)
              at org.jboss.weld.bootstrap.BeanDeployment.<init>(BeanDeployment.java:85)
              at org.jboss.weld.bootstrap.WeldBootstrap$DeploymentVisitor.visit(WeldBootstrap.java:197)
              at org.jboss.weld.bootstrap.WeldBootstrap$DeploymentVisitor.visit(WeldBootstrap.java:174)
              at org.jboss.weld.bootstrap.WeldBootstrap.startContainer(WeldBootstrap.java:295)
              at org.glassfish.weld.WeldDeployer.event(WeldDeployer.java:151)
              ... 30 more



      It seems odd that a framework writer would not be able to automatically turn on a set of interceptors from their library, and instead needs to require that the end-user include a (possibly long) list of enabled interceptors, and I don't see any reference in the spec of this restriction -- in fact, section 9.4 of the spec has a paragraph that reads An interceptor is said to be enabled if it is enabled in at least one bean archive., implying that it would be possible to enable it from multiple archives.. am I missing something here?  Is there way to write a framework or CDI extension, and not require the end user to include a list of 7 or 8 interceptors by hand?


      M

        • 1. Re: Enabling an interceptor in a library
          gavin.king

          Yes, this is a serious bug, that I reported last week.

          • 2. Re: Enabling an interceptor in a library
            william.drai

            Could you give precisions on how the ordering of interceptors is done when many extensions define their own interceptors in beans.xml.


            I guess it is undefined except if the application redefines all interceptors in its own beans.xml.

            • 3. Re: Enabling an interceptor in a library
              nickarls

              I think they are just listed in the order they happen to appear in the list of URLs to beans.xml files in the bean deployment archive and according to the tree of reachable bean managers(?)

              • 4. Re: Enabling an interceptor in a library

                Thanks for the update, Gavin -- is there a ballpark release date for the 1.0.1 release?

                • 5. Re: Enabling an interceptor in a library
                  gavin.king

                  William Draï wrote on Dec 02, 2009 11:52:


                  Could you give precisions on how the ordering of interceptors is done when many extensions define their own interceptors in beans.xml.

                  I guess it is undefined except if the application redefines all interceptors in its own beans.xml.



                  Nono, interceptor ordering is per-module. So each module has its own list of interceptors, with its own well-defined ordering. There is no application-global interceptor ordering, since there are no application-gobal interceptors.


                  Does that make sense?

                  • 6. Re: Enabling an interceptor in a library
                    gavin.king

                    Nicklas Karlsson wrote on Dec 02, 2009 12:25:


                    I think they are just listed in the order they happen to appear in the list of URLs to beans.xml files in the bean deployment archive and according to the tree of reachable bean managers(?)


                    No, definitely not.

                    • 7. Re: Enabling an interceptor in a library
                      william.drai

                      I understand that the interceptor chain is per module.


                      But what happens if I have 3 jars with an extension that defines SomeUsefulInterceptor in beans.xml of its own jar, a second extension that defines EvenMoreUsefulInterceptor, and the application module itself that has only TotallyUselessInterceptor in beans.xml.


                      Do you mean that only TotallyUselessInterceptor will be enabled for the app module ?

                      • 8. Re: Enabling an interceptor in a library
                        gavin.king

                        Exactly. The module would need to declare all three interceptors explicitly in its own beans.xml. I really think this is the Right Thing :-)

                        • 9. Re: Enabling an interceptor in a library
                          william.drai

                          If I understand correctly, that means that what Matt tries to do wouln't work (defining an interceptor in a library jar beans.xml) even without the bug you indicate.


                          And that's not what I've observed in the current version of Weld/JBoss 6. My interceptor defined in the beans.xml of an extension jar is happily applied to all beans of all my other ejb jar modules (and that perfectly fits my need). I've no idea what would be the order of interceptors for now as I've only one :-)


                          As for the Right Thing to do, I think what Matt (and I) want to do is correct, and it would be strange to force users of extensions to define all the extension interceptors manually in their beans.xml.


                          At least, there should be a way to do something like this :


                          <interceptors>
                             <class>...</class>
                             <extension>...</extension>  => All interceptors of the extension applied here
                             <class>...</class>
                          </interceptors>
                          


                          • 10. Re: Enabling an interceptor in a library
                            gavin.king

                            If I understand correctly, that means that what Matt tries to do wouln't work (defining an interceptor in a library jar beans.xml) even without the bug you indicate.

                            Right. You must declare interceptors in the module in which they are to be used, not in the module in which they are packaged. :-)



                            And that's not what I've observed in the current version of Weld/JBoss 6. My interceptor defined in the beans.xml of an extension jar is happily applied to all beans of all my other ejb jar modules

                            OK, then that is a bug. Please report it in JIRA.



                            (and that perfectly fits my need). I've no idea what would be the order of interceptors for now as I've only one :-)

                            Right, so it's perfectly fine when you've got just one interceptor. Once you have lots of modules in your application, along with several portable extensions, each defining their own interceptors, it's going to be a total clusterfuck :-)


                            So, like I said, what the spec says is the Right Thing :-)



                            At least, there should be a way to do something like this :

                            <interceptors>
                               <class>...</class>
                               <extension>...</extension>  => All interceptors of the extension applied here
                               <class>...</class>
                            </interceptors>



                            Hrm, that's not a bad idea, however I don't expect that many extensions are going to define multiple interceptors.


                            By the way, I'm planning the next release of CDI to include a programmatic way to register interceptors/decorators/alternatives. Namely, a Module object, and a ProcessModule event in the portable extension SPI.


                            So you would be able to magically register interceptors with that. Whether it would be a Good Idea, I doubt :-)

                            • 11. Re: Enabling an interceptor in a library
                              william.drai

                              Having many interceptors for an extension is not necessarily the problem. But exposing the internal implementation (i.e. the interceptor class) of the extension to the user does not look as a Good Idea :-) I would like to be able to change the class names of my interceptors without breaking all applications using my extensions.


                              I agree that automatic registration of interceptors can lead to a total clusterfuck (never seen this word before, I like it so much that I felt an absolute necessity to reuse it somewhere immediately), but on the other hand non-automatic registration complicates the installation of extensions that in most cases could be as simple as putting a jar in WEB-INF/lib (or adding a dependency to pom.xml for maven lovers). This problem of ordering resembles to what happens with the new web-fragment feature of servlet 3, I don't know how it's handled there.

                              • 12. Re: Enabling an interceptor in a library
                                nickarls

                                Gavin King wrote on Dec 02, 2009 16:34:

                                No, definitely not.


                                Yes, if you interpret me correctly ;-)


                                What I was saying that a BeanDeploymentArchive can have multiple beans.xml (although there is usually only one for a file-based one). And if each beans.xml enables some interceptors, the order of them will be the order of the files (keeping the order within each single file). Well, URL, not always file.


                                The reachable managers-stuff was of course a brain fart...

                                • 13. Re: Enabling an interceptor in a library
                                  gavin.king

                                  But exposing the internal implementation (i.e. the interceptor class) of the extension to the user does not look as a Good Idea :-)

                                  Yes, I also don't love this, but I don't see any better solution to the problem of ordering interceptors defined in different portable extensions, We have to guarantee deterministic behavior here, we can't have the container just set them up in a random order at runtime.


                                  Now, I guess what you're suggesting is to introduce some additional indirection - a string based name or annotation - instead of using the bare class name, but I don't really see that very much is to be gained by that.



                                  This problem of ordering resembles to what happens with the new web-fragment feature of servlet 3, I don't know how it's handled there.

                                  Yes, it's a very similar problem. I'm not a big fan of their solution, frankly. Go take a look at the new servlet spec. I think what they have is probably OK for the problems they're working with, but it wouldn't be OK, IMO, for what we're doing.

                                  • 14. Re: Enabling an interceptor in a library
                                    gavin.king

                                    What I was saying that a BeanDeploymentArchive can have multiple beans.xml (although there is usually only one for a file-based one). And if each beans.xml enables some interceptors, the order of them will be the order of the files (keeping the order within each single file). Well, URL, not always file.

                                    A single bean archive can have multiple beans.xml files? Really? What for?

                                    1 2 Previous Next