We were developing an application with Seam 2.2.2.EAP5.
This app was packaged as an EAR with a WAR and 2 jars on its root (besides jboss-seam.jar).
The app was working fine until we did a little refactor (we moved ProcessesServiceBean and its interface from one jar into the EAR to the another one). After this, this error started to happen when accessing the bean:
19:31:10,044 INFO [ServerImpl] JBoss (Microcontainer) [5.1.0 (build: SVNTag=JBPAPP_5_1_0 date=201009150028)] Started in 1m:29s:57ms
19:31:38,682 ERROR [Exceptions] handled and logged exception
org.jboss.seam.InstantiationException: Could not instantiate Seam component: CrearSolicitudBB
at org.jboss.seam.Component.newInstance(Component.java:2170)
at org.jboss.seam.Component.getInstance(Component.java:2024)
at org.jboss.seam.Component.getInstance(Component.java:1986)
at org.jboss.seam.Component.getInstance(Component.java:1980)
at org.jboss.seam.Namespace.getComponentInstance(Namespace.java:55)
at org.jboss.seam.Namespace.getComponentInstance(Namespace.java:50)
at org.jboss.seam.el.SeamELResolver.resolveBase(SeamELResolver.java:148)
at org.jboss.seam.el.SeamELResolver.getValue(SeamELResolver.java:51)
at javax.el.CompositeELResolver.getValue(CompositeELResolver.java:54)
at com.sun.faces.el.FacesCompositeELResolver.getValue(FacesCompositeELResolver.java:72)
at org.jboss.el.parser.AstIdentifier.getValue(AstIdentifier.java:44)
at org.jboss.el.parser.AstValue.getValue(AstValue.java:63)
at org.jboss.el.parser.AstEqual.getValue(AstEqual.java:21)
at org.jboss.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:186)
at org.jboss.seam.core.Expressions$1.getValue(Expressions.java:112)
at org.jboss.seam.navigation.Action.isExecutable(Action.java:21)
at org.jboss.seam.navigation.Page.preRender(Page.java:302)
at org.jboss.seam.navigation.Pages.preRender(Pages.java:351)
at org.jboss.seam.jsf.SeamPhaseListener.preRenderPage(SeamPhaseListener.java:561)
at org.jboss.seam.jsf.SeamPhaseListener.beforeRenderResponse(SeamPhaseListener.java:472)
at org.jboss.seam.jsf.SeamPhaseListener.beforeServletPhase(SeamPhaseListener.java:148)
at org.jboss.seam.jsf.SeamPhaseListener.beforePhase(SeamPhaseListener.java:118)
at com.sun.faces.lifecycle.Phase.handleBeforePhase(Phase.java:214)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:96)
at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:266)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83)
at org.jboss.seam.web.IdentityFilter.doFilter(IdentityFilter.java:40)
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
at org.jboss.seam.web.MultipartFilter.doFilter(MultipartFilter.java:90)
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
at org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64)
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
at org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:45)
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
at org.ajax4jsf.webapp.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:178)
at org.ajax4jsf.webapp.BaseFilter.handleRequest(BaseFilter.java:295)
at org.ajax4jsf.webapp.BaseFilter.processUploadsAndHandleRequest(BaseFilter.java:373)
at org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:500)
at org.jboss.seam.web.Ajax4jsfFilter.doFilter(Ajax4jsfFilter.java:56)
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
at org.jboss.seam.web.LoggingFilter.doFilter(LoggingFilter.java:60)
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
at org.jboss.seam.web.HotDeployFilter.doFilter(HotDeployFilter.java:53)
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
at org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:235)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:183)
at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:95)
at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.process(SecurityContextEstablishmentValve.java:126)
at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:70)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:330)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:829)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:598)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:451)
at java.lang.Thread.run(Thread.java:619)
Caused by: java.lang.IllegalArgumentException: value of context variable is not an instance of the component bound to the context variable: processesServiceBean. If you are using hot deploy, you may have attempted to hot deploy a session or application-scoped component definition while using an old instance in the session.
at org.jboss.seam.Component.getInstance(Component.java:2040)
at org.jboss.seam.Component.getInstance(Component.java:1986)
at org.jboss.seam.Component.getInstance(Component.java:1980)
at org.jboss.seam.Component.getInstanceInAllNamespaces(Component.java:2375)
at org.jboss.seam.Component.getValueToInject(Component.java:2327)
at org.jboss.seam.Component.injectAttributes(Component.java:1739)
at org.jboss.seam.Component.inject(Component.java:1557)
at org.jboss.seam.core.BijectionInterceptor.aroundInvoke(BijectionInterceptor.java:61)
at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
at org.jboss.seam.bpm.BusinessProcessInterceptor.aroundInvoke(BusinessProcessInterceptor.java:51)
at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
at org.jboss.seam.core.MethodContextInterceptor.aroundInvoke(MethodContextInterceptor.java:44)
at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
at org.jboss.seam.intercept.RootInterceptor.invoke(RootInterceptor.java:107)
at org.jboss.seam.intercept.JavaBeanInterceptor.interceptInvocation(JavaBeanInterceptor.java:185)
at org.jboss.seam.intercept.JavaBeanInterceptor.invoke(JavaBeanInterceptor.java:103)
at ar.com.test.web.bb.CrearSolicitudBB_$$_javassist_seam_3.load(CrearSolicitudBB_$$_javassist_seam_3.java)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.jboss.seam.util.Reflections.invoke(Reflections.java:22)
at org.jboss.seam.util.Reflections.invokeAndWrap(Reflections.java:144)
at org.jboss.seam.Component.callComponentMethod(Component.java:2275)
at org.jboss.seam.Component.callCreateMethod(Component.java:2198)
at org.jboss.seam.Component.newInstance(Component.java:2158)
... 67 more
Notes:
1) We have not hot deployed
2) We have made a clean on all jars, wars and ears before building (using Maven). We also deleted all the components in maven's local repo.
3) We have stopped, deleted tmp, data and work folders and then started
4) We are not using Seam 3 in none of the POMs
5) We have also tried calling the component with different names.
PROBLEM:
It was a classloader problem.
The backing bean was inside the WAR and its classloader was: jboss.classloader:id="vfszip:/opt/jboss/jboss-eap-5.1/jboss-as/server/test/deploy/test/test-web.war/")
The other Seam component was inside the jar and its classloader was:
(jboss.classloader:id="vfszip:/opt/jboss/jboss-eap-5.1/jboss-as/server/test/deploy/test.ear/")
SOLUTION:
Copy test/META-INF/jboss-classloader.xml to test/test-web.war/WEB-INF
jboss-classloader.xml:
classloading xmlns="urn:jboss:classloading:1.0" domain="test" all="NON_EMPTY" first="true"
martes, 24 de mayo de 2011
martes, 4 de mayo de 2010
Configuración de JBoss Messaging en cluster y sin persistencia
Escribo esta entrada porque no está muy clara en la documentación oficial ( http://www.jboss.org/file-access/default/members/jbossmessaging/freezone/docs/userguide-1.3.0.GA/html/c_configuration.html) cómo configurar JBoss Messaging en cluster y sin persistencia.
Estos son los pasos:
<mbean code="org.jboss.jms.server.destination.QueueService"
name="jboss.messaging.destination:service=Queue,name=ClusteredExampleQueue"
xmbean-dd="xmdesc/Queue-xmbean.xml">
<depends optional-attribute-name="ServerPeer">jboss.messaging:service=ServerPeer</depends>
<depends>jboss.messaging:service=PostOffice</depends>
<attribute name="Clustered">true</attribute>
</mbean>
<!-- This post office is clustered. If you don't want a clustered post office then set to false -->
<attribute name="Clustered">true</attribute>
THIS SHOULD ALWAYS BE CHANGED AT INSTALL TIME TO SECURE SYSTEM
<attribute name="SuckerPassword"></attribute>
-->
Por defecto la distribución de mensajes entre distintos nodos está habilitada. Esto significa que si un nodo está ocioso le pedirá a los otros nodos que le pasen mensajes para procesar. Esto es útil si los nodos procesan mensajes de forma heterogénea.
Si se desea deshabilitar comentar en messaging-service.xml la siguiente sección:
<!-- The name of the connection factory to use for creating connections between nodes to pull messages -->
<attribute name="ClusterPullConnectionFactoryName">jboss.messaging.connectionfactory:service=ClusterPullConnectionFactory</attribute>
-->
Estos son los pasos:
- Agregar la cola clusterizada en deploy/jboss-messaging.sar/destinations-service.xml:
<mbean code="org.jboss.jms.server.destination.QueueService"
name="jboss.messaging.destination:service=Queue,name=ClusteredExampleQueue"
xmbean-dd="xmdesc/Queue-xmbean.xml">
<depends optional-attribute-name="ServerPeer">jboss.messaging:service=ServerPeer</depends>
<depends>jboss.messaging:service=PostOffice</depends>
<attribute name="Clustered">true</attribute>
</mbean>
- Reemplazar deploy/jboss-messaging.sar/clustered-hsqldb-persistence-service.xml por jboss-as/docs/examples/null-persistence-service (en hsqldb usa Hypersonic y por ende no está preparado para producción). Si se desea usar persistencia entonces usar el clustered-
-persistence-service.xml adecuado.
- Editar el archivo null-persistence-service y setear el atributo clustered en true:
<!-- This post office is clustered. If you don't want a clustered post office then set to false -->
<attribute name="Clustered">true</attribute>
- Agregar un password para el mesage sucker. Este password debe ser el mismo en todos los nodos. Para esto descomentar y completar este elemento de deploy/jboss-messaging.sar/messaging-service.xml:
THIS SHOULD ALWAYS BE CHANGED AT INSTALL TIME TO SECURE SYSTEM
<attribute name="SuckerPassword"></attribute>
-->
- Agregar -Djboss.messaging.ServerPeerID=1 (siendo 1 el número del nodo) a las opciones de arranque del JBoss. Es indispensable que el número no se repita entre diferentes nodos.
Por defecto la distribución de mensajes entre distintos nodos está habilitada. Esto significa que si un nodo está ocioso le pedirá a los otros nodos que le pasen mensajes para procesar. Esto es útil si los nodos procesan mensajes de forma heterogénea.
Si se desea deshabilitar comentar en messaging-service.xml la siguiente sección:
<!-- The name of the connection factory to use for creating connections between nodes to pull messages -->
<attribute name="ClusterPullConnectionFactoryName">jboss.messaging.connectionfactory:service=ClusterPullConnectionFactory</attribute>
-->
martes, 26 de enero de 2010
JBoss Messaging: User null is NOT authenticated
2010-01-25 17:09:01,415 ERROR [org.jboss.resource.adapter.jms.inflow.JmsActivation] Unable to reconnect org.jboss.resource.adapter.jms.inflow.JmsActivationSpec@33cf0f(ra=org.jboss.resource.adapter.jms.JmsResourceAdapter@173089d destination=queue/RulesQueueMock destinationType=javax.jms.Queue tx=true durable=false reconnect=10 provider=java:/DefaultJMSProvider user=null maxMessages=1 minSession=1 maxSession=15 keepAlive=60000 useDLQ=true DLQHandler=org.jboss.resource.adapter.jms.inflow.dlq.GenericDLQHandler DLQJndiName=queue/DLQ DLQUser=null DLQMaxResent=5)
javax.jms.JMSSecurityException: User null is NOT authenticated
at org.jboss.jms.server.security.SecurityMetadataStore.authenticate(SecurityMetadataStore.java:200)
at org.jboss.jms.server.endpoint.ServerConnectionFactoryEndpoint.createConnectionDelegateInternal(ServerConnectionFactoryEndpoint.java:233)
at org.jboss.jms.server.endpoint.ServerConnectionFactoryEndpoint.createConnectionDelegate(ServerConnectionFactoryEndpoint.java:171)
at org.jboss.jms.server.endpoint.advised.ConnectionFactoryAdvised.org$jboss$jms$server$endpoint$advised$ConnectionFactoryAdvised$createConnectionDelegate$aop(ConnectionFactoryAdvised.java:108)
at org.jboss.jms.server.endpoint.advised.ConnectionFactoryAdvised.createConnectionDelegate(ConnectionFactoryAdvised.java)
at org.jboss.jms.wireformat.ConnectionFactoryCreateConnectionDelegateRequest.serverInvoke(ConnectionFactoryCreateConnectionDelegateRequest.java:91)
at org.jboss.jms.server.remoting.JMSServerInvocationHandler.invoke(JMSServerInvocationHandler.java:143)
at org.jboss.remoting.ServerInvoker.invoke(ServerInvoker.java:862)
at org.jboss.remoting.transport.local.LocalClientInvoker.invoke(LocalClientInvoker.java:101)
at org.jboss.remoting.Client.invoke(Client.java:1858)
at org.jboss.remoting.Client.invoke(Client.java:718)
at org.jboss.jms.client.delegate.ClientConnectionFactoryDelegate.org$jboss$jms$client$delegate$ClientConnectionFactoryDelegate$createConnectionDelegate$aop(ClientConnectionFactoryDelegate.java:178)
at org.jboss.jms.client.delegate.ClientConnectionFactoryDelegate$createConnectionDelegate_N3019492359065420858.invokeNext(ClientConnectionFactoryDelegate$createConnectionDelegate_N3019492359065420858.java)
at org.jboss.jms.client.container.StateCreationAspect.handleCreateConnectionDelegate(StateCreationAspect.java:80)
at org.jboss.aop.advice.org.jboss.jms.client.container.StateCreationAspect0.invoke(StateCreationAspect0.java)
at org.jboss.jms.client.delegate.ClientConnectionFactoryDelegate$createConnectionDelegate_N3019492359065420858.invokeNext(ClientConnectionFactoryDelegate$createConnectionDelegate_N3019492359065420858.java)
at org.jboss.jms.client.delegate.ClientConnectionFactoryDelegate.createConnectionDelegate(ClientConnectionFactoryDelegate.java)
at org.jboss.jms.client.JBossConnectionFactory.createConnectionInternal(JBossConnectionFactory.java:205)
at org.jboss.jms.client.JBossConnectionFactory.createQueueConnection(JBossConnectionFactory.java:101)
at org.jboss.jms.client.JBossConnectionFactory.createQueueConnection(JBossConnectionFactory.java:95)
at org.jboss.resource.adapter.jms.inflow.dlq.AbstractDLQHandler.setupDLQConnection(AbstractDLQHandler.java:137)
at org.jboss.resource.adapter.jms.inflow.dlq.AbstractDLQHandler.setup(AbstractDLQHandler.java:83)
at org.jboss.resource.adapter.jms.inflow.dlq.JBossMQDLQHandler.setup(JBossMQDLQHandler.java:48)
at org.jboss.resource.adapter.jms.inflow.JmsActivation.setupDLQ(JmsActivation.java:381)
at org.jboss.resource.adapter.jms.inflow.JmsActivation.setup(JmsActivation.java:327)
at org.jboss.resource.adapter.jms.inflow.JmsActivation.handleFailure(JmsActivation.java:271)
at org.jboss.resource.adapter.jms.inflow.JmsActivation$SetupActivation.run(JmsActivation.java:675)
at org.jboss.resource.work.WorkWrapper.execute(WorkWrapper.java:213)
at org.jboss.util.threadpool.BasicTaskWrapper.run(BasicTaskWrapper.java:275)
at EDU.oswego.cs.dl.util.concurrent.PooledExecutor$Worker.run(PooledExecutor.java:756)
at java.lang.Thread.run(Thread.java:595)
El tema es que el usuario guest que necesita el JBM lo crea el
Si no queremos usar persistencia ni BD, lo que conviene hacer es editar el login-config.xml, y reemplazar el application policy de "messaging" que utiliza una base de datos por el que usa archivos planos (u otro login module) tal como está explicado en http://www.jboss.org/file-access/default/members/jbossmessaging/freezone/docs/userguide-1.4.0.SP3/html/installation.html#install.manual.
sábado, 19 de diciembre de 2009
Nuevo libro de jBPM

Tuve el agrado de ser uno de los revisores del libro de Salaboy:
jBPM Developer Guide que acaba de salir de la imprenta. Lo interesante del libro es que te introduce en el código fuente de jBPM, justificando así el comportamiento del motor de jBPM e invitando a contribuir al mismo.
Felicitaciones Mauricio por este gran trabajo!!
viernes, 20 de marzo de 2009
Integración transparente de funcionalidad volátil en UI de aplicaciones web
Las aplicaciones web están siempre en evolución contínua. En respuesta a cambios de requerimientos se desarrolla código adicional y se modifica el existente. Cuando los requerimientos son temporarios (es decir, cuando se espera que estén presentes en la aplicación durante algún tiempo para luego ser removidos), el código adicionado debe ser removido en el futuro. Esta forma de proceder, además de demandar tiempo y esfuerzo, involucra la múltiple edición del código original de la aplicación, con el riesgo de ensuciarlo o introducir errores.
Ahora acaban de publicar en JWE un paper sobre este tema que escribimos con Gustavo Rossi, Matías Urbieta y Damiano Distante. El mismo es una edición ampliada y más detallada de este otro.
Nuestra propuesta para lidiar con el problema a nivel UI se basa en la composición transparente de interfaces de usuario y está inspirado en técnicas de separación avanzada de concerns, tales com AOP. De esta forma logramos una clara separación de las interfaces del core de la aplicación con respecto a las correspondientes a funcionalidad volátil. Las UI core no se percatan de la existencia de las UI volátiles y pueden ser compuestas de manera transparente en runtime mediante transformaciones XSL.
De esta forma se simplifica la evolución de la aplicación evitando ediciones indeseadas del código de las core UI.
Ahora acaban de publicar en JWE un paper sobre este tema que escribimos con Gustavo Rossi, Matías Urbieta y Damiano Distante. El mismo es una edición ampliada y más detallada de este otro.
Nuestra propuesta para lidiar con el problema a nivel UI se basa en la composición transparente de interfaces de usuario y está inspirado en técnicas de separación avanzada de concerns, tales com AOP. De esta forma logramos una clara separación de las interfaces del core de la aplicación con respecto a las correspondientes a funcionalidad volátil. Las UI core no se percatan de la existencia de las UI volátiles y pueden ser compuestas de manera transparente en runtime mediante transformaciones XSL.
De esta forma se simplifica la evolución de la aplicación evitando ediciones indeseadas del código de las core UI.
jueves, 19 de marzo de 2009
Habilitación del caché de prepared statements de JBoss
La reutilización de prepared statements permite a la base de datos reusar el plan de acceso, lo cual mejora la performance si un mismo statement es ejecutado varias veces. La ganancia de performance puede ser de hasta un 10%.
Sin embargo, debido a una mala interpretación de la especificación JDBC 3, algunos drivers deOracle no soportan correctamente auto-commit=false (http://www.jboss .org/community/docs/DOC-9328). Por este motivo el caché de preparedStatement está deshabilitado por defecto en la configuración de JBoss .
Para asegurarnos rápidamente que el driver que están usando soporta correctamente auto-commit=false he implementado un pequeño test que verifica el correcto funcionamiento del driver, el cual pueden descargar de http://www.4shared.com/file/93886002/681b749f/autoCommitTest.html(avisen si el link está roto)
Para usarlo:
-Modificar en eljboss -service de adentro de autoCommitTest.sar el nombre del datasource Oracle y de la tabla
- Desplegar en /deploy
- Acceder al MBean mediante la JMX-console y presionar "performTest"
- Si obtienen una respuesta exitosa entonces pueden habilitar sin miedo el caché
Sin embargo, debido a una mala interpretación de la especificación JDBC 3, algunos drivers de
Para asegurarnos rápidamente que el driver que están usando soporta correctamente auto-commit=false he implementado un pequeño test que verifica el correcto funcionamiento del driver, el cual pueden descargar de http://www.4shared.com/file/93886002/681b749f/autoCommitTest.html(avisen si el link está roto)
Para usarlo:
-Modificar en el
- Desplegar en /deploy
- Acceder al MBean mediante la JMX-console y presionar "performTest"
- Si obtienen una respuesta exitosa entonces pueden habilitar sin miedo el caché
domingo, 15 de marzo de 2009
WAR/EAR classloaders
Un clásico: tenemos un componente web empaquetado como un WAR que realiza invocaciones de métodos a otro componente de negocio empaquetado como un EAR.
En la invocación a métodos se envían objetos de clases X.class. Esta clase X está presente en un librería JAR que es compartida por el WAR y EAR (de hecho este JAR está incluído en el WAR y EAR). Asumimos que la clase X es la misma en los dos paquetes.
Estamos usando el JBoss 4.2.2 con la configuración default.
Cuando intentamos invocar al método desde el WAR obtenemos un maldito "ClassCastException".
Qué es lo que está pasando?
El tema de los classloaders es un problema complejo. Intentaré ser breve y claro:
Por defecto el WAR usa un classloader propio (lo cual en ciertas circunstancias es bueno porque permite desplegar aplicaciones web sin problema de conflicto de clases con otra aplicación).
El EAR por su lado utiliza un unified classloader propio (UCL) que está asociado con el UnifiedLoaderRepository de JBoss. Este último es un repositorio de clases que permite a las diferentes aplicaciones que se ejecutan en JBoss compartir clases.
La clase X en consecuencia está levantada por dos classloaders diferentes. Como para Java2 la identidad en runtime de una clase está definida por el fully qualified class name más su defining class loader, la JVM va a interpretar que la clase X que levantó un classloader es diferente de la misma clase levantada por otro classloader. De ahí surge el ClassCastException.
Cómo solucionarlo
Discutiremos diferentes soluciones
- Sacar el JAR compartido del WAR y el EAR y ponerlo en el directorio lib de la configuración de JBoss.
Puede andar, sin embargo si ese JAR depende de otras librerías que están en el WAR o en el EAR podemos llegar a terminar metiendo un montón de librerías específicas de la aplicación en el lib. Por otro lado el hecho que un WAR o EAR ya contenga sus librerías facilita su instalación en otras plataformas.
- Forzar el pasaje por valor para la comunicación entre el WAR y EAR
Horrible si está en la misma JVM!
- Hacer que el Tomcat use un UCL
Para esto hay que editar el archivo jboss-web.deployer/META-INF/jboss-service.xml y setear el atributo "UseJBossWebLoader" en true:
<!-- A flag indicating if the JBoss Loader should be used. This loader
uses a unified class loader as the class loader rather than the tomcat
specific class loader.
The default is false to ensure that wars have isolated class loading
for duplicate jars and jsp files.
-->
<attribute name="UseJBossWebLoader">true</attribute>
De esta forma las clases cargadas por las aplicaciones web serán compartidas por las demás aplicaciones que se ejecutan en JBoss.
En la invocación a métodos se envían objetos de clases X.class. Esta clase X está presente en un librería JAR que es compartida por el WAR y EAR (de hecho este JAR está incluído en el WAR y EAR). Asumimos que la clase X es la misma en los dos paquetes.
Estamos usando el JBoss 4.2.2 con la configuración default.
Cuando intentamos invocar al método desde el WAR obtenemos un maldito "ClassCastException".
Qué es lo que está pasando?
El tema de los classloaders es un problema complejo. Intentaré ser breve y claro:
Por defecto el WAR usa un classloader propio (lo cual en ciertas circunstancias es bueno porque permite desplegar aplicaciones web sin problema de conflicto de clases con otra aplicación).
El EAR por su lado utiliza un unified classloader propio (UCL) que está asociado con el UnifiedLoaderRepository de JBoss. Este último es un repositorio de clases que permite a las diferentes aplicaciones que se ejecutan en JBoss compartir clases.
La clase X en consecuencia está levantada por dos classloaders diferentes. Como para Java2 la identidad en runtime de una clase está definida por el fully qualified class name más su defining class loader, la JVM va a interpretar que la clase X que levantó un classloader es diferente de la misma clase levantada por otro classloader. De ahí surge el ClassCastException.
Cómo solucionarlo
Discutiremos diferentes soluciones
- Sacar el JAR compartido del WAR y el EAR y ponerlo en el directorio lib de la configuración de JBoss.
Puede andar, sin embargo si ese JAR depende de otras librerías que están en el WAR o en el EAR podemos llegar a terminar metiendo un montón de librerías específicas de la aplicación en el lib. Por otro lado el hecho que un WAR o EAR ya contenga sus librerías facilita su instalación en otras plataformas.
- Forzar el pasaje por valor para la comunicación entre el WAR y EAR
Horrible si está en la misma JVM!
- Hacer que el Tomcat use un UCL
Para esto hay que editar el archivo jboss-web.deployer/META-INF/jboss-service.xml y setear el atributo "UseJBossWebLoader" en true:
<!-- A flag indicating if the JBoss Loader should be used. This loader
uses a unified class loader as the class loader rather than the tomcat
specific class loader.
The default is false to ensure that wars have isolated class loading
for duplicate jars and jsp files.
-->
<attribute name="UseJBossWebLoader">true</attribute>
De esta forma las clases cargadas por las aplicaciones web serán compartidas por las demás aplicaciones que se ejecutan en JBoss.
Suscribirse a:
Entradas (Atom)