You can find the full source code for this website in the Seam package in the directory /examples/wiki. It is licensed under the LGPL.
| Forum: Weld Users |
02. Dec 2009, 05:26 America/New_York | Link |
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
Yes, this is a serious bug, that I reported last week.
Learn more about Weld...
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.
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(?)
If a man speaks in the forest and there is no woman around to hear him, is he still wrong?
Thanks for the update, Gavin -- is there a ballpark release date for the 1.0.1 release?
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?
Learn more about Weld...
No, definitely not.
Learn more about Weld...
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 ?
Exactly. The module would need to declare all three interceptors explicitly in its own beans.xml. I really think this is the Right Thing :-)
Learn more about Weld...
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 :
Right. You must declare interceptors in the module in which they are to be used, not in the module in which they are packaged. :-)
OK, then that is a bug. Please report it in JIRA.
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 :-)
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 :-)
Learn more about Weld...
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.
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 -stuff was of course a brain fart...
If a man speaks in the forest and there is no woman around to hear him, is he still wrong?
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.
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.
Learn more about Weld...
A single bean archive can have multiple beans.xml files? Really? What for?
Learn more about Weld...
Dunno. Pete wrote it ;-)
A while back I had a theory in another thread for autoconfiguring applications that could enable an alternative stereotype from a know JNDI key by adding another beans.xml to the deployment archive...
If a man speaks in the forest and there is no woman around to hear him, is he still wrong?
I did some refactoring that might have touched this area, do you still have your deployment archive and do you think you could attach it to https://jira.jboss.org/jira/browse/WELD-319 ?
If a man speaks in the forest and there is no woman around to hear him, is he still wrong?
I can think of lots of ways to do it -- the details don't really matter, as long as it is explicitly defined (something Java EE specs have been bad at historically, but which the CDI spec does a good job of)...
For the record, I can live with the current solution, but would prefer a standard ordering mechanism, with some way to override it in a given module... having to expose the interceptor class name is a bit smelly -- even using the InterceptorBinding would be more palatable, but I recognize this is really a different thing...
An extension that defines a Transactional interceptor to handle the various EJB TransactionTypeAttributes could have six, if they're implemented separately, so I think it's quite feasible... Any shop who adopts CDI as an internal framework platform could have several interceptors over time to handle transactions, logging, security, etc -- I think it's quite likely that this will be more common than you think, especially if CDI gets the traction that I think it will :)
Again, though, I think the current solution is workable, and is far better than simply leaving it up to the implementation...
M
But try to think what would be the situation in JSF if it requires every component (view handler, navigation handler, phase-listener) to be configured in WEB-INF/faces-config.xml. This configuration file should expose a lot of implementation details.
In JSF the ordering is not well defined, but at 95% it's ok. Usually extensions work on different aspects so also if the order is not deterministic this doesn't cause issues.
Because of success of CDI and CDI extensions, I think you said the ;)
Funny, it was actually my (bad) experience with JSF extensions that convinced me that we really needed to have a well-defined, deterministic ordering here :-)
I don't think you realize the pain and suffering that framework developers go through to ensure that you guys get a 95% ok user experience :-)
Trust me - it does.
Hehe, you could be right. But I'm not worried, it's going to be easy for us to add something additional here, if and when the need arises.
Learn more about Weld...
Ok you are right, but I realized today that JSF 2.0 tried to solve the faces-config.xml ordering.
http://snipurl.com/tmbz5
If I read well they let specify a name for every faces-config.xml so that the main configuration file can define an order using this names.
I guess left over from old version of SPI, for 1.1 we can probably remove it.
BTW JBoss AS also has another bug in this area - it doesn't describe the module structure well enough.
https://jira.jboss.org/jira/browse/WELDINT-1
Read about how to report a bug.