h1

Como montar Spring en Sun Application Server

06/21/2007

Wizdoc [Icon By Buuf]

 Tips & Tricks

Como parte de mi función de arquitecto, he realizado la instalación de varias aplicaciones sobre el Sun Java System Application Server, Enterprise Edition. Las versiones del Application Server sobre las que he trabajado han variado desde la 8.0, 8.1 y 8.2, hasta el Glassfish (equivalente a la versión 9).

Asimismo, también se ha requerido de mi parte el verificar que estas aplicaciones se encuentren adheridas a la especificación JEE y que sigan mínimamente las recomendaciones sugeridas por los Sun enterprise patterns – por ejemplo, que los desarrolladores utilicen los pools de conexiones ofrecidos por el contenedor, o que exista una nomenclatura estándar entre los paquetes que componen sus aplicaciones.

Tomando esto en cuenta, el pasado martes se requirió que instalara una aplicación que incluye varios frameworks de desarrollo, incluyendo Tapestry, web services desarrollados en Axis y Spring. De todos, Spring ha sido el framework que más lata dió al pasarlo del ambiente de desarrollo del programador (Apache Tomcat 6.0.10) a su nuevo dominio dentro de los servidores de desarrollo del cliente (un servidor Sun Fire V240 con la versión 8.2 del Application Server), al grado que de primera instancia mucha gente considera que este servidor no soporta Spring. Ooops.

Sin embargo, armándose de paciencia y aplicándose una A+ en Google Search, existe una manera relativamente sencilla de montar Spring sobre el SJSAS 8.2:

1. Instalación de módulo web (.war) en instancia del application server:


Instalación del aplicativo en el SJSAS 8.2

2. La instalación marcó un error al subir la aplicación:

[#|2007-06-19T11:23:43.547-0500|SEVERE|sun-appserver-ee8.2|org.springframework.web.context.ContextLoader|_ThreadID=15;|Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘locator’ defined in ServletContext resource [/WEB-INF/app/core/conf/core-cfg.xml]: Cannot resolve reference to bean ‘accessControllerCfg’ while setting bean property ‘modules’ with key [accessController]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘accessControllerCfg’ defined in ServletContext resource [/WEB-INF/app/core/conf/core-cfg.xml]: Cannot resolve reference to bean ‘accessController’ while setting bean property ‘module’; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘accessController’ defined in ServletContext resource [/WEB-INF/app/core/conf/core-cfg.xml]: Instantiation of bean failed; nested exception is java.security.AccessControlException: access denied (java.lang.reflect.ReflectPermission suppressAccessChecks)
org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘accessControllerCfg’ defined in ServletContext resource [/WEB-INF/app/core/conf/core-cfg.xml]: Cannot resolve reference to bean ‘accessController’ while setting bean property ‘module’; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘accessController’ defined in ServletContext resource [/WEB-INF/app/core/conf/core-cfg.xml]: Instantiation of bean failed; nested exception is java.security.AccessControlException: access denied (java.lang.reflect.ReflectPermission suppressAccessChecks)
org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘accessController’ defined in ServletContext resource [/WEB-INF/app/core/conf/core-cfg.xml]: Instantiation of bean failed; nested exception is java.security.AccessControlException: access denied (java.lang.reflect.ReflectPermission suppressAccessChecks)
java.security.AccessControlException: access denied (java.lang.reflect.ReflectPermission suppressAccessChecks)
    at java.security.AccessControlContext.checkPermission(AccessControlContext.java:264)
    at java.security.AccessController.checkPermission(AccessController.java:427)
    at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
    at java.lang.reflect.AccessibleObject.setAccessible(AccessibleObject.java:107)
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:169)
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:148)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:52)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:486)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:362)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:233)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:145)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:186)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:106)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1046)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:857)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:378)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:233)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:145)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:186)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:106)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveManagedMap(BeanDefinitionValueResolver.java:235)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:118)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1046)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:857)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:378)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:233)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:145)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:283)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:313)
    at org.springframework.web.context.support.AbstractRefreshableWebApplicationContext.refresh(AbstractRefreshableWebApplicationContext.java:139)
    at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:252)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:190)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:49)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4010)
    at org.apache.catalina.core.StandardContext.start(StandardContext.java:4521)
    at com.sun.enterprise.web.WebModule.start(WebModule.java:241)
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:827)
    at org.apache.catalina.core.ContainerBase.access$000(ContainerBase.java:125)
    at org.apache.catalina.core.ContainerBase$PrivilegedAddChild.run(ContainerBase.java:147)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:809)
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:646)
    at com.sun.enterprise.web.WebContainer.loadWebModule(WebContainer.java:1331)
    at com.sun.enterprise.web.HttpServiceWebContainer.loadWebModule(HttpServiceWebContainer.java:867)
    at com.sun.enterprise.web.WebContainer.loadWebModule(WebContainer.java:1040)
    at com.sun.enterprise.server.WebModuleDeployEventListener.moduleDeployed(WebModuleDeployEventListener.java:160)
    at com.sun.enterprise.server.WebModuleDeployEventListener.moduleRedeployed(WebModuleDeployEventListener.java:308)
    at com.sun.enterprise.admin.event.AdminEventMulticaster.invokeModuleDeployEventListener(AdminEventMulticaster.java:922)
    at com.sun.enterprise.admin.event.AdminEventMulticaster.handleModuleDeployEvent(AdminEventMulticaster.java:905)
    at com.sun.enterprise.admin.event.AdminEventMulticaster.processEvent(AdminEventMulticaster.java:427)
    at com.sun.enterprise.admin.event.AdminEventMulticaster.multicastEvent(AdminEventMulticaster.java:139)
    at com.sun.enterprise.ee.admin.mbeans.ServerRuntimeMBean.forwardEvent(ServerRuntimeMBean.java:64)
    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:585)
    at com.sun.enterprise.admin.MBeanHelper.invokeOperationInBean(MBeanHelper.java:305)
    at com.sun.enterprise.admin.runtime.BaseRuntimeMBean.invoke(BaseRuntimeMBean.java:386)
    at com.sun.jmx.mbeanserver.DynamicMetaDataImpl.invoke(DynamicMetaDataImpl.java:213)
    at com.sun.jmx.mbeanserver.MetaDataImpl.invoke(MetaDataImpl.java:220)
    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:815)
    at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:784)
    at sun.reflect.GeneratedMethodAccessor21.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:585)
    at com.sun.enterprise.admin.util.proxy.ProxyClass.invoke(ProxyClass.java:54)
    at $Proxy1.invoke(Unknown Source)
    at com.sun.enterprise.admin.server.core.jmx.SunoneInterceptor.invoke(SunoneInterceptor.java:272)
    at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1408)
    at javax.management.remote.rmi.RMIConnectionImpl.access$100(RMIConnectionImpl.java:81)
    at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1245)
    at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1341)
    at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:782)
    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:585)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:294)
    at sun.rmi.transport.Transport$1.run(Transport.java:153)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:149)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:466)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:707)
    at java.lang.Thread.run(Thread.java:595)
|#]
3. Este error es relacionado al nivel de seguridad con el que cuenta la librería spring.jar – específicamente, a la falta de permisos para invocar métodos protegidos o privados mediante reflexión. Para corregirlo, es necesario incluir los permisos correspondientes (java.security.AllPermission) al archivo de políticas del servidor (server.policy). De aquí se desprenden dos situaciones:

3.1. La librería spring.jar se encuentra embebida dentro del directorio WEB-INF/lib del war; esto no es recomendable porque con relativa frecuencia, varias aplicaciones implementadas con el mismo framework residen en el mismo dominio; esto implica carga de las mismas clases una y otra vez mediante el classloader de Java y en algunos casos puede volverse un problema de desempeño. Por limpieza general, siempre es recomendable que los frameworks se encuentren instalados en el classpath de la aplicación, no embebida en ésta.

Nota: Tampoco es aconsejable dejar dichas librerías instaladas en el classpath del servidor, (${com.sun.aas.installRoot}/lib) porque a menos que TODAS las aplicaciones estén implementadas con los mismos frameworks y misma versión de los mismos, puede generarse un problema de incompatibilidad de versiones en tiempo de ejecución.

3.2. Al encontrarse la librería dentro del jar, para asignar los permisos necesarios, tendrían que ser asignados a TODO el war, lo que equivale a "apagar" la seguridad para la aplicación. Dicho riesgo de seguridad es inaceptable.

Por ambos motivos es necesario extraer la librería del war y dejarla en un directorio aparte.

4. El procedimiento de extracción/generación de permisos para spring.jar fue el siguiente:

4.1. Se eliminó spring.jar del directorio WEB-INF/lib dentro del war.

4.2. Dicha librería se depositó dentro del directorio lib en el dominio donde se ejecutará la aplicación:

${com.sun.aas.installRoot}/domains/
    ${administrative.domain.name}/lib/frameworks/
    spring/spring.jar

donde:
${com.sun.aas.installRoot} = ROOT de instalación del application server (por ejemplo /opt/SunAppServer).
${administrative.domain.name} = Nombre del dominio donde está corriendo la aplicación (por ejemplo, domain1).

4.3. Se agregó la librería al classpath del dominio, modificando el archivo domain.xml localizado en la siguiente ruta:

${com.sun.aas.installRoot}/domains/
    ${administrative.domain.name}/config

4.4. Se asignaron los permisos de seguridad al archivo server.policy localizado en la siguiente ruta:

${com.sun.aas.installRoot}/domains/
    ${administrative.domain.name}/config

Al agregar las siguientes líneas al final de dicho archivo:

//Permissions added to Spring classes
grant codeBase "file:${com.sun.aas.installRoot}/domains/
    ${administrative.domain.name}/lib/frameworks/
    spring/spring.jar" {
    permission java.security.AllPermission;
};

Mediante este procedimiento deberían correr la mayoría de las aplicaciones con Spring en cualquiera de las versiones del Sun Application Server.

Sin embargo, para este caso especial, se está utilizando la funcionalidad de JMX (Java Management Extensions) desde Spring. Esto provoca otro error en tiempo de despliegue:

[#|2007-06-19T14:43:00.266-0500|SEVERE|sun-appserver-ee8.2|org.springframework.web.context.ContextLoader|_ThreadID=10;|Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘mbeanExporter’ defined in ServletContext resource [/WEB-INF/app/core/conf/core-cfg.xml]: Initialization of bean failed; nested exception is java.security.AccessControlException: access denied (javax.management.MBeanTrustPermission register)
java.security.AccessControlException: access denied (javax.management.MBeanTrustPermission register)
    at java.security.AccessControlContext.checkPermission(AccessControlContext.java:264)
    at java.lang.SecurityManager.checkPermission(SecurityManager.java:568)
    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.checkMBeanTrustPermission(DefaultMBeanServerInterceptor.java:1724)
    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerMBean(DefaultMBeanServerInterceptor.java:335)
    at com.sun.jmx.mbeanserver.JmxMBeanServer.registerMBean(JmxMBeanServer.java:497)
    at sun.reflect.GeneratedMethodAccessor5.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:585)
    at com.sun.enterprise.admin.util.proxy.ProxyClass.invoke(ProxyClass.java:54)
    at $Proxy1.registerMBean(Unknown Source)
    at com.sun.enterprise.admin.server.core.jmx.SunoneInterceptor.registerMBean(SunoneInterceptor.java:249)
    at org.springframework.jmx.export.MBeanExporter.doRegister(MBeanExporter.java:566)
    at org.springframework.jmx.export.MBeanExporter.registerMBean(MBeanExporter.java:485)
    at org.springframework.jmx.export.MBeanExporter.registerBeanInstance(MBeanExporter.java:461)
    at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:441)
    at org.springframework.jmx.export.MBeanExporter.registerBeans(MBeanExporter.java:368)
    at org.springframework.jmx.export.MBeanExporter.afterPropertiesSet(MBeanExporter.java:312)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1091)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:396)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:233)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:145)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:283)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:313)
    at org.springframework.web.context.support.AbstractRefreshableWebApplicationContext.refresh(AbstractRefreshableWebApplicationContext.java:139)
    at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:252)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:190)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:49)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4010)
    at org.apache.catalina.core.StandardContext.start(StandardContext.java:4521)
    at com.sun.enterprise.web.WebModule.start(WebModule.java:241)
    at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1086)
    at org.apache.catalina.core.StandardHost.start(StandardHost.java:847)
    at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1086)
    at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:483)
    at org.apache.catalina.startup.Embedded.start(Embedded.java:894)
    at com.sun.enterprise.web.WebContainer.start(WebContainer.java:741)
    at com.sun.enterprise.web.HttpServiceWebContainer.startInstance(HttpServiceWebContainer.java:935)
    at com.sun.enterprise.web.HttpServiceWebContainerLifecycle.onStartup(HttpServiceWebContainerLifecycle.java:50)
    at com.sun.enterprise.server.ApplicationServer.onStartup(ApplicationServer.java:300)
    at com.sun.enterprise.server.PEMain.run(PEMain.java:294)
    at com.sun.enterprise.server.PEMain.main(PEMain.java:220)
|#]
Cuya resolución es muy parecida a la del error anterior:

Se asignaron los permisos de seguridad al archivo server.policy localizado en la siguiente ruta:

${com.sun.aas.installRoot}/domains/
    ${administrative.domain.name}/config

Incluyendo la línea correspondiente al registro de Managed Beans – MBeans a la declaración de permisos de la librería spring.jar:

//Permissions added to Spring classes
grant codeBase "file:${com.sun.aas.installRoot}/domains/
    ${administrative.domain.name}/lib/frameworks/
    spring/spring.jar" {
    permission java.security.AllPermission;
    permission javax.management.MBeanTrustPermission "register";
};

Finalmente, se incluye la configuración apropiada en el JRE para que exista la capacidad de asignar este permiso, incluyendo las siguiente líneas:

// JMX Management Extension added for spring framework
permission javax.management.MBeanTrustPermission "register";

En el archivo de políticas de seguridad de Java:

${com.sun.aas.javaRoot}/jre/lib/security/java.security

Donde ${com.sun.aas.javaRoot} = Directorio de instalación de Java (por ejemplo, como el application server ya trae una JVM, el directorio sería /opt/SunAppServer/JDK).

Conclusiones

Después de estas adecuaciones a la seguridad del entorno de Java y la refactorización de los componentes web de la aplicación, ésta levanta sin ningún problema y no se registran errores durante el tiempo de ejecución. El único punto que queda por mencionar con respecto al Sun Application Server es que es un tanto melindroso, y que para subir aplicaciones, éstas deben adherirse a la especificación JEE prácticamente al 100% para que puedan correr. Eso es bueno y malo, ya que por un lado detalles como el aspecto de la seguridad deben estar bien definidos e implementados; por otro, se limita un poco la difusión del SJSAS debido a que muchos desarrolladores prefieren un app server con funcionalidad DMFJ[1] instalada.


Notas y pies de página

1.DMFJ = Do My F*cking Job

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: