Posts Tagged spring

Spring, JPA y DBUnit

Como ahora tengo bastante tiempo libre, he empezado una aplicación para prototipar algunos conceptos que me interesa fijar. Así, he comenzado por resolver la arquitectura básica de persistencia. He decidido usar Spring y JPA (Hibernate). Y para las pruebas he querido usar también DbUnit para llenar una base de datos en memoria (H2).

Y como estaba bastante oxidado, estuve viendo las nuevas anotaciones en Spring 2 y me llamó la atención el estereotipo . Dado que encaja muy bien con el enfoque de “modelo rico” en el que quiero trabajar, he estado jugando con esto y ha quedado así.

Comenzaré por el test.

@ContextConfiguration(locations = {"classpath:/META-INF/dao-test-context.xml"})
public class UserRepositoryTest extends AbstractRepositoryTest {

@Autowired
private UserDAO userDAO;

@Test
public void testFindByUsername() {
User aUser = userDAO.findByUsername("rob");
assertEquals("0001", aUser.getId());
assertEquals("Robert", aUser.getName());
assertEquals("Smith", aUser.getSurname());
}



La anotación permite decir dónde están los ficheros de configuración de Spring (para nuestro ejemplo sólo usamos uno, pero se pueden poner todos los que se quieran). Con inyectamos el DAO que vamos a probar sin necesidad de declararlo en el xml.

El código de la clase abstracta de la que extendemos tiene la “fixture” de la base de datos usando DbUnit.


@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class,TransactionalTestExecutionListener.class})
@Transactional
public class AbstractRepositoryTest {

private static String TEST_DATA_FILE = "src/test/resources/dbunit-test-data.xml";

/** Logger available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());

@Autowired
private DataSource dataSource;

private DataSource getDataSource() {
return this.dataSource;
}

@BeforeTransaction
public void onSetUpInTransaction() throws Exception {
logger.info("*** Inserting test data ***");
// Use spring to get the datasource
DataSource ds = getDataSource();
Connection conn = ds.getConnection();
try {
IDatabaseConnection connection = new DatabaseConnection(conn);
DatabaseOperation.CLEAN_INSERT.execute(connection,
new FlatXmlDataSet(new FileInputStream(TEST_DATA_FILE),false));
} finally {
DataSourceUtils.releaseConnection(conn, ds);
logger.info("*** Finished inserting test data ***");
}
}

@AfterTransaction
public void onTearDownInTransaction() throws Exception {
// Delete the data
DataSource ds = getDataSource();
Connection conn = ds.getConnection();
try {
IDatabaseConnection connection = new DatabaseConnection(conn);
DatabaseOperation.DELETE.execute(connection, new FlatXmlDataSet(
new FileInputStream(TEST_DATA_FILE)));
} finally {
DataSourceUtils.releaseConnection(conn, ds);
logger.info("*** Finished removing test data ***");
}
}



El “truco” aquí consiste en la anotación y la inyección de DataSource (que está declarada en el xml de Spring).

El repositorio lo implementamos como un DAO, pero en vez de heredar de JpaDaoSupport (que es quizás lo más común cuando usamos Spring) lo implementamos independiente de Spring (aunque añadamos la anotación @Repository). Cuando usamos , el contenedor de Spring “sabe” cómo inyectar el EntityManager sin que tengamos que decirle nada explícitamente.


@Repository
public class JpaUserDAO implements UserDAO {

private EntityManager entityManager;

@PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}

public EntityManager getEntityManager() {
return entityManager;
}

public User findByUsername(final String username) {
return (User) getEntityManager().
createQuery("from User where username = :username").
setParameter("username", username).
getSingleResult();
}





Como es JPA, es necesario el fichero META-INF/persistence.xml.


<persistence version="1.0">
xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">

<persistence-unit name="ACME_PU-TEST" transaction-type="RESOURCE_LOCAL">
<class>acme.core.users.User</class>
</persistence-unit>

</persistence>



Obsérvese que apenas hay que darle información. Tenemos que explicitar qué tenemos (podemos hacerlo en un fichero orm.xml, pero por simplicidad lo he dejado dentro).

Y finalmente, el pegamento de todo esto… el xml de Spring.


<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd"
default-autowire="byName">

<context:component-scan base-package="acme.core"/>
<context:annotation-config/>

<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="databasePlatform" value="org.hibernate.dialect.H2Dialect"/>
<property name="showSql" value="true"/>
<property name="generateDdl" value="true"/>
</bean>
</property>
<property name="persistenceUnitName" value="ACME_PU-TEST"/>
</bean>

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="org.h2.Driver"/>
<property name="url" value="jdbc:h2:mem:test_mem"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"/>

</beans>


Es importante señalar que hay dos partes en este xml (de hecho, los he fusionado para que resultara más compacto, pero realmente los tengo separados): los elementos del espacio de nombres “context” y “beans” respectivamente.

Las primeras son necesarias para poder usar y otras. Las otras son los únicos tres beans que necesitamos declarar en el xml (porque no son nuestros sino implementaciones que vienen con la librería de Spring).

Es importante declarar los tres y usar esos nombres para aprovechar la inyección automática “byName”.

Falta el xml con los datos para que DbUnit cree la tabla y rellene los datos de prueba (nuestra “fixture”).


<?xml version="1.0" encoding="UTF-8"?>
<dataset>
<user id="0001" username="rob" name="Robert" surname="Smith" />
<user id="0002" username="rob2" name="Robert" surname="Jones" />
<user id="0003" username="peter" name="Peter" surname="Mullins" />
</dataset>



Espero que os sea útil. A continuación os explicaré cómo implementar una capa de servicios que use este repositorio de datos, con sus pruebas de aceptación (con Concordion, por supuesto) y todo… :-)

Tags: , , ,

Webinar "Introduction to Spring DM"

La semana pasada SpringSource ofreció el webinar titulado “Introduction to Spring Dynamic Modules”. Ya está disponible en su versión grabada.

Lo siento, pero yo lo he intentado con Firefox y no he conseguido verlo, de modo que necesitaréis Internet Explorer y elegir la opción de “Redifusión” (porque la otra no funciona). Espero que SpringSource abandone esta plataforma Microsoft Live Meeting para sus webinars porque es seriamente mejorable. :-(

Si alguien encuentra esta presentación en un formato más “portable”, por favor que me avise. Gracias.

Tags: ,

Interface21 cambia su nombre a Spring Source

Los creadores del framework Spring acaban de cambiar su nombre de Interface21 a Spring Source. Como ellos mismos dicen en su web: “el nombre lo dice todo”.

Este cambio de nombre coincide con la liberación de la versión 2.5 del framework (que aparece con todos sus jars “osgificados”, es decir, listos para ser incorporados en un contenedor OSGi) y con la liberación de la primera “release candidate” de la versión 1.0 del proyecto Spring Dynamic Modules (aka Spring:OSGi).

Tags: ,

PAX : OSGi made easy

Estas últimas semanas tengo bastante abandonado este blog porque estamos comenzando un proyecto muy bonito a la vez que difícil (al menos para mi): estamos valorando la posibilidad de desarrollar nuestro framework SOA basándolo en OSGi y SCA. Para ello, mi compañero Sixto está montando Newton con Spring:OSGi y todo el entorno de desarrollo que nos permita construir y desplegar nuestras aplicaciones en este nuevo entorno. Y en este orden de cosas, hemos visto que hay un par de herramientas muy nuevas que nos van a permitir acelerar muchas tareas: se trata de pax-runner y pax-construct.

Aquellos que tengáis algo que ver con OSGi, no perdáis ni un momento en echar un vistazo a este proyecto PAX (dentro de otro proyecto más genérico, OPS4J) porque merece la pena: puedes configurar tu entorno de ejecución y lanzar el contenedor de tu elección (por defecto es Apache Felix) con extrema facilidad (un fichero txt). Y muy similar es el proceso de construir una aplicación, incluso puedes “osgificar” un jar sin más que ejecutar pax-construct.

Este proyecto es un gran reto para mi, pero también por eso mismo está siendo tan apasionante.


Powered by ScribeFire.

Tags: , , , ,

Tuscany SCA + Spring

Acabo de conseguir echar a andar uno de los ejemplos de Tuscany SCA en el que se muestra cómo usarlo con la extensión Spring. Está todo mavenizado pero hay que hacer algún “hack” porque hay dependencias SNAPSHOT que aún no han sido liberadas.

  1. Hay que hacer checkout desde https://svn.apache.org/repos/asf/incubator/tuscany/java/sca/samples/simple-bigbank-spring. Yo lo he hecho desde mi Eclipse 3.3 con JDK 6 y con el plugin m2 para Maven. Así, en mi workspace tengo el proyecto “simple-bigbank-spring” pero ni compila ni nada.
  2. Botón derecho + “Enable Dependency Management” para habilitar el plugin de Maven.
  3. Botón derecho + “Properties” para revisar el classpath:
    • Añadir la librería del JRE (yo he puesto la que tengo por defecto: JDK 6)
    • Quitar el directorio raíz del proyecto como carpeta para el código fuente y seleccionar los estándar de Maven: src/main/java, src/main/resources y src/test/java.
    • Cambiar el directorio destino de las clases compiladas de “bin” a “target/classes”.
    • Pulsar “OK” y aceptar que se borre el contenido de “bin”.
  4. Tocar el pom.xml:
    • Añadir el repositorio de snapshots de apache: http://people.apache.org/repo/m2-snapshot-repository
    •    <repository>      <id>apache.snapshot</id>      <url>http://people.apache.org/repo/m2-snapshot-repository</url>   </repository>

    • Eliminar el elemento “relativePath” del “parent”.
    • Cambiar todas las dependencias 1.1-incubating-SNAPSHOT por 1.0-incubating-SNAPSHOT.
  5. (Es posible que tengáis que deshabilitar y volver a habilitar las dependencias de Maven para que pille estos cambios).
  6. Ejecutar el goal “install” con Maven, lo cuál descargará bastantes librerías, y al final deberíais tener el proyecto perfectamente compilado y listo para ejecutar.
  7. Ejecutad la única prueba en src/test/java/bigbank/BigBankTestCase (con botón derecho “Run As Junit Test”).

El resultado en la consola es:

log4j:WARN No appenders could be found for logger (org.apache.tuscany.sca.implementation.spring.SCAApplicationContext).
log4j:WARN Please initialize the log4j system properly.
Spring parent context – getBean called for name: stockQuoteService
Getting stock quote for: IBM, value: 104.73
Account summary: currency: USD, [ID:Foo_CHA12345, balance:1500.0, ID:Foo_SAA12345, balance:1500.0, ID:Foo_STA12345, symbol:IBM, quantity:100, balance:10473.0]

Tags: ,

SCA

He estado leyendo el libro “Service-Oriented Architecture (SOA): Concepts, Technology, and Design” de Thomas Erl y he llegado al convencimiento (entre otras muchas cosas) de que para hacer “verdadero SOA” son necesarios:
  • una infraestructura que haga posible la localización y la colaboración (síncrona o asíncrona) entre servicios
  • buscar un modelo a partir del cuál poder diseñar los servicios como componentes estándar (independientemente de la infraestructura en la que se desplieguen)

Respecto al segundo punto, leyendo, leyendo y navegando, navegando, he llegado a una serie de artículos de IBM sobre integración usando SOA. Tras leer varios de ellos (reconozco que no todos), he visto que SCA sería una posible solución. Para los que quieran una introducción rápida a SCA, creo que es mejor acudir a la fuente directamente. En la web de OpenSOA se define el modelo en UML, por si eso ayuda en algo a su comprensión. Lo mejor de todo es que ya hay incluso especificación para API Java y ejemplos de cómo usar JAX-WS para implementar un componente “SCA-enabled”.

SCA es una propuesta OASIS (por lo que se garantiza que Microsoft también participa y que, por tanto, está garantizado el éxito en la interoperabilidad). A mí, sin embargo, me queda la duda (y me gustaría mucho que alguien me lo explicara) sobre qué diferencia hay entre SCA y JBI y entre SCA y WSIT. Lo que pasa es que la gente de Glassfish parece un poco escéptica al respecto de adoptar SCA (al menos tal cual está ahora definida). Ya le pregunté “in person” a Eduard Pelegrí y me contestó que él veía más factible una convergencia a medio/largo plazo de JBI (Sun) y SCA (IBM).

De todos modos, vamos a ver, que yo sepa… SOA no sólo se puede implementar con .NET o con J2EE;-)

Tags: , , , ,