Luisete

De profesión sus labores

  • Aumentar fuente
  • Fuente predeterminada
  • Disminuir fuente
Home Informática Arquitectura JSJ

Arquitectura JSJ

E-mail Imprimir PDF

Aún a riesgo de hacernos caer en un nuevo golden hammer, las anotaciones han venido a salvarnos de la tiranía del XML. La arquitectura JSJ (JSF 2.0+Spring+JPA) permite minimizar el uso de XML de configuración hasta el límite a costa de maximizar el uso de anotaciones, todo ello dentro de una adaptación del patrón MVC model 2.

Lo bonito de todo esto es que por fin vamos a poder desarrollar una aplicación MVC de forma razonable, sin que nos de un soponcio cada vez que tengamos que hacer algún cambio y sin tener que taparnos la nariz.

 

Lo que voy a mostrar a continuación es una gran simplificación. No pretendo ser ni exhaustivo ni preciso , sino expresar la esencia de la arquitectura, aunque a la vez pueda servir de casi tutorial.

En la imagen de la derecha podemos ver un ejemplo muy esquemático de la relación entre capas. Cada rectángulo representa un elemento de cada capa (Web, Control, Servicios, y Persistencia). El modelo se considera transversal, y puede ser utilizado por tanto en cualquier capa.

Persona.xhtml representa una página JSF 2.0 en la que podemos hacer referencia a los llamados ManagedBeans a través del lenguaje EL. Cuando queremos utilizar una referencia a un atributo o un método de un ManagedBean lo hacemos con la forma "#{xxxx}". En este ejemplo vemos que se está solicitando el campo nombre de una entidad persona que forma parte del controlador personaCtl y que ofrecemos un botón que al pulsarlo invocará el método grabar de la clase PersonaCtl.

PersonaCtl.java  es un ManagedBean controlador. Gracias a la versión 2.0 podemos declararlo simplemente con la anotación @ManagedBean sin necesidad de tocar ficheros XML. El ciclo de vida de este objeto va dirigido por JSF y lo podemos matizar para que sea de request, sesión, etc. Dentro de un controlador podemos tener métodos que sean invocados desde las páginas JSF 2.0. El convenio es que el retorno de estos métodos es un String que si no se dice nada en contra podrá ser el nombre de la vista , página web, a la que queremos navegar tras ejecutar la acción. 

Vemos también que declaramos una instancia miembro de PersonaServicio que va precedida de la anotación @ManagedProperty. Mediante esta anotación le decimos a JSF2.0 que nos inyecte una instancia del servicio obteniéndola a través de su EL-Resolver. En este caso la propiedad es un servicio que declaramos con Spring, así que necesitaremos tunear el EL-Resolver de JSF2.0 para que sea capaz de devolvernos Beans del mundo de Spring. Lo veremos más abajo. Mientras tanto tengamos fé.

PersonaServicioImpl es la implementación de un servicio de la capa de la lógica de negocio. El interfaz no lo representamos aquí por ser obvio. Lo importante de esta clase son de nuevo sus anotaciones. A saber. Utilizamos la anotación @Service para  decirle a Spring que esto es un Bean de la capa de servicios. Por defecto creará una instancia única (Singleton) por lo que debemos cuidar mucho no guardar estado en el servicio.

La anotación @Transactional le dice a Spring que antes de invocar a este servicio se inicie una transacción si es necesario. Podemos matizar muchos detalles referentes a la transacción y la propagación. Vamos a quedarnos de momento con el valor por defecto. En defnitiva, que queremos que siempre que se invoque al servicio se haga dentro de una transaccción y que se haga commit automáticamente al terminar excepto si termino con una excepción de runtime. 

Vemos también la anotación @Autowired que es de Spring y le dice a la variable miembro dao que debe ser instanciada automáticamente obteniendo un bean de PersonaDAO. Tengo que ofrecer un método setDao que no está incluido en la imagen para ser lo más concisos posible.

PersonaDAOImpl.java es una clase de la capa de persistencia. Se marca mediante la anotación de Spring @Repository y gracias a ello es inyectable como vimos en el servicio. 

La anotación @PersistenceContext es cuasi-mágica. Gracias a ella Spring nos inyectará automáticamente un EntityManager, pero atención, nos inyecta lo que se llama un Shared EntityManager, el cual permite la concurrencia. Está demostrado que con este mecanismo, dos hilos concurrentes en la práctica es como si tuvieran dos EntityManager diferentes a efectos de aislamiento. Así que gracias a esto no nos tenemos que preocupar de nada.

Por otro lado también será normal tener un DAO genérico del cual podemos heredar para no tener que hacer la implementación de cada DAO, pero esto se sale un poco del tamaño del artículo.

Persona.java es la clase del modelo de datos de nuestra aplicación y se debe anotar con @Entity para que JPA cuente con ella a la hora de persistir. Es obligatorio la anotación que declara el identificador de la clase ó clave principal y muy recomendable la anotación @GeneratedValue para que la clave sea autonumerada. 

Métodos set: Ojo , por razones de concreción no he incluído los métodos set de las propiedades inyectadas en todas las clases anteriores, pero que no se nos olviden que son necesarios unos métodos públicos setXxxx para que Spring nos pueda inyectar sus valores.

Configuración

Hasta ahora no hemos escrito nada de configuración en XML. Solamente tenemos que hacer un truco para poder enganchar JSF con Spring y es declararle a JSF un EL-REsolver de Spring para que pueda encontrar Beans de este segundo y usarlos como propiedades en JSF. Para ello, escribimos el siguiente faces-config.xml:

   <application>
   		<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
   </application>

Y por otro lado tendremos que tener un mínimo applicationContext.xml en el cual configurar el EntityManager, el DataSource y donde le debemos decir que nos busque las anotaciones por nuestros paquetes para encontrar los beans:

	<context:component-scan base-package="es.microsocial"/>	 
	<context:annotation-config/> 		 	
	<tx:annotation-driven/> 		 	
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">         
		<property name="driverClass"><value>org.hsqldb.jdbcDriver</value></property>        
		 <property name="jdbcUrl"><value>jdbc:hsqldb:hsql://localhost/</value></property>         
		<property name="user"><value>sa</value></property> 
	        <property name="password"><value></value></property>        
		 <property name="properties">             
		<props>                  
			<prop key="c3p0.acquireRetryAttempts">5</prop>            
		 </props>         
		</property>    
	 </bean> 		 		 
	<bean id="entityManagerFactory"      		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">      
		<property name="dataSource" ref="dataSource"/> 	 
		<property name="jpaVendorAdapter"> 	       
		 <bean 	        class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> 	          
			<property name="showSql" value="false" />
	 	        <property name="generateDdl" value="true" /> 	         
			<property name="databasePlatform" value="org.hibernate.dialect.HSQLDialect" /> 	        
		</bean> 	     
	</property> 	
	</bean>  	  
 
	<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 	    
		<property name="entityManagerFactory" ref="entityManagerFactory"/> 	    
		<property name="dataSource" ref="dataSource"/> 	  
	</bean>			 

Finalmente, nuestro web.xml tiene que estar preparado para el uso de JSF 2.0 y de Spring. Se reproducen a continuación las partes clave del web.xml que se refieren a ello:

     <context-param>     
	    <param-name>contextConfigLocation</param-name>         
		<param-value>             /WEB-INF/applicationContext.xml         </param-value>            
	 </context-param>          
	<listener> 		
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
       </listener>     
	<servlet> 	
		<servlet-name>Faces Servlet</servlet-name> 		
		<servlet-class>javax.faces.webapp.FacesServlet</servlet-class> 
	</servlet> 
	<servlet-mapping> 		
		<servlet-name>Faces Servlet</servlet-name> 	
		<url-pattern>*.jsf</url-pattern> 	
	</servlet-mapping> 	
 

Librerías

La implementación de referencia de JSF 2.0  se llama Mojarra y es la que mejor funciona a la fecha de este artículo. Son simplemente dos ficheros ".jar" que tenemos que tener en nuestro WEB-INF/lib. Se trata de jsf-api.jar y jsf-impl.jar que nos podemos descargar directamente de la página de Mojarra

La implementación de Spring que he utilizado yo es la 2.5 , aunque lógicamente servirá cualquier implementación posterior.

Necesitamos una implementación de JPA que bien puede ser la de Hibernate.

 

 

LAST_UPDATED2