Perfiles de desarrollo y producción con Maven

Algo muy común y recomendable en cualquier proyecto medianamente serio es contar con un servidor de desarrollo y otro de producción, además del propio equipo del programador donde se hacen las primeras pruebas. Los programas se prueban en local, se prueban en desarrollo y finalmente, cuando se ha verificado que todo está correcto, se puede pasar a producción donde se explotará una BD con datos reales y habrá usuarios reales. Hay lugares en los que incluso existe una servidor de pre-producción.

Lo normal en cualquier proyecto mínimamente cuerdo es que el desarrollo se haga con una BD con la misma estructura que la BD de producción pero por supuesto con datos inventados. La configuración del programa por tanto es distinta en desarrollo y en producción. Si los programadores han sido mínimamente serios, deben haber programado el acceso a los datos de una forma que el código no tenga que variar en un entorno u otro. Lo ideal es que la configuración del acceso a la BD (driver, url, nombre, password) más otras configuraciones estén aisladas en un único fichero de propiedades (properties, xml, lo que sea, pero aislado). De esta forma, cuando pasamos el proyecto de desarrollo a producción lo único que debe variar es el fichero de configuración.

Lo que pasa es que según el tipo de proyecto, si la aplicación esta comprimida por ejemplo en un jar o en un war y dentro contiene ese ficherillo de configuración tenemos que ser capaces de generar un fichero de proyecto para desarrollo y otro para producción.

Maven controla

Esta situación tan típica está prevista en Maven. En Maven podemos definir los profiles o perfiles que nos permite aplicar distintas propiedades (BD, usuario, password) al proyecto, y lo que es más interesante, automáticamente puede propagar esas propiedades a ficheros properties, a ficheros de contexto spring, o a cualquier fichero que metamos dentro de la carpeta resources.

settings.xml

Para poder definir los tipos de entorno o perfil en los que trabajamos (desarrollo, producción) y para poder decirle a Maven cuál de ellos se debe aplicar por defecto, dentro de nuestra carpeta Maven ($HOME/.m2) debemos incluir un fichero xml llamado settings.xml cuyo contenido es bastante evidente:




	
		dev
		
			
			true
		
		
			dev
		
	
	
		preproduction
		
		false
		
		
			preproduction
		
	
	
		production
		
		false
		
		
			production
		
	


Los ficheros properties

Vamos a ver qué aspecto tienen dos ficheros cuyos valores queremos que cambien según el perfil que queramos aplicar. Como veremos, en lugar de poner valores se ponen variables. Los dos se encuentran en la carpeta resources del proyecto Maven (src/main/resources). Por un lado un fichero properties normalito:

database.driverClassName=${database.driverClassName}
database.url=${database.url}
database.user=${database.user}
database.password=${database.password}
anyvalue=${anyvalue.name}
othervalue=This is just a test

Y por otro un fichero xml de contexto de Spring.

...


		
		
		
		




	

...
El pom.xml

Y ahora viene cuando la matan. Dentro del fichero de proyecto Maven es donde vamos a definir las propiedades de cada perfil. Si NO queremos que esos datos sean visibles para todo aquel que maneja este fichero, podemos separar la parte de las properties y llevarlas al fichero settings.xml que también contiene una sección properties por cada perfil. Es importante incluir la parte final del build resources ya que sin ella no se propagan las variables.


  4.0.0

  info.pello.maven.profilessample
  MavenProfiles
  0.0.1-SNAPSHOT
  jar

  MavenProfiles
  http://maven.apache.org

  
  		
		1.6
		UTF-8
		UTF-8
  
  
 
 	
	
		  
			development
			
				
					environment.type
					dev
				
			
			
				com.mysql.jdbc.Driver
				jdbc:mysql://localhost:3306/erp-dev
				dev-user
				dev-user
				God
			
	
	
	  
			production
			
				
					environment.type
					production
				
			
			
				com.mysql.jdbc.Driver
				jdbc:mysql://localhost:3306/erp-prod
				prod-user
				prod-password
				Satan
			
	
  


  
    
      junit
      junit
      3.8.1
      test
    
  
  
  
    
        
            
                src/main/resources
                true
            
        
    


¿Y cómo aplico esto?

Bien, por defecto se aplicará el perfil dev. Podemos verificar qué perfiles tenemos activados con el siguiente comando:

linux:~/workspace/MavenProfiles# mvn help:active-profiles
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'help'.
[INFO] ------------------------------------------------------------------------
[INFO] Building MavenProfiles
[INFO]    task-segment: [help:active-profiles] (aggregator-style)
[INFO] ------------------------------------------------------------------------
[INFO] [help:active-profiles {execution: default-cli}]
[INFO] 
Active Profiles for Project 'info.pello.maven.profilessample:MavenProfiles:jar:0.0.1-SNAPSHOT': 

The following profiles are active:

 - dev (source: settings.xml)
 - dev (source: settings.xml)

Si queremos que se aplique el perfil de production debemos ejecutar lo siguiente:

linux:~/workspace/MavenProfiles# mvn install -Denvironment.type=production
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Building MavenProfiles
[INFO]    task-segment: [install]
[INFO] ------------------------------------------------------------------------
[INFO] [resources:resources {execution: default-resources}]
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 2 resources
[INFO] [compiler:compile {execution: default-compile}]
...

Para que cambie el contenido de los ficheros de desarrollo a producción NO ES NECESARIO HACER CLEAN, mvn install mantiene el mismo código compilado pero sí propaga las propiedades.

Esto lo podemos hacer desde eclipse también. En un proyecto basado en Maven, podemos crear distintos run configurations, en concreto un Maven Build..., uno que haga un install normal y otro al que le digamos que queremos un perfil distinto, con lo que conseguimos el objetivo final: aplicar uno u otro con un simple click

Aplicando un install de producción

Y así es como quedaría por ejemplo el fichero properties tal y como se guarda en la carpeta target o dentro del jar:

linux:~/workspace/MavenProfiles# more target/classes/myproject.properties 
database.driverClassName=com.mysql.jdbc.Driver
database.url=jdbc:mysql://localhost:3306/erp-prod
database.user=prod-user
database.password=prod-password
anyvalue=Satan
othervalue=This is just a test

linux:~/workspace/MavenProfiles#

Asier jambo ¿ves qué fácil? Págate algo.

by Pello Altadill 08/17/2013 22:16:00 - 700 hits

Hilos en Android con Threads java

Toda aplicación de Android tiene al menos un hilo o thread de ejecución. Ese thread es el encargado de la pantalla que tienes ante ti y es imprescindible por la manera en la que Android gestiona los cambios en el interfaz: a través de una cola de mensajes. Es decir, cada vez que aplicamos algún cambio en algún View no se aplica directamente sino que se deja la petición en una cola. Y ese hilo, el UI thread o el hilo principal de la aplicación es quien precisamente se encarga de procesar esa cola...

by Pello Altadill 08/17/2013 10:50:52 - 823 hits

More »

Servidor web de Node.js refactorizado

Sí, seguro que el primer código que has visto de Node.js es uno de esos milagrosos servidores web hechos con pocas líneas. Olvídese de aparatosos sockets, de punteros o de BufferedStreamsWriters, un módulo, unos callbacks, eliges un puerto y a dar servicio. Bueno, uno trata de ser un good Node.js citizen y este código se entiende y mola, pero a la larga, si lo queremos ir mejorando y añadiendo otras funcionalidades cada vez va a ser más complicado mantenerlo. Lo que propongo en ...

by Pello Altadill 08/16/2013 23:18:31 - 384 hits

More »

Hibernate self-join con anotaciones

Vamos a dejar por unos instantes tanto Javascript sin tipos y sin estructura y pongámonos otra vez la corbata para volver al mainstream de aplicaciones empresariales J2EE. Quedaba pendiente ver cómo montar un self-join pero con anotaciones, es decir una clase que se hace referencia a sí misma. En su momento ya puse aquí la versión con el mapeo por XML, vamos a ver cómo quedaría la cosa pero usando las anotaciones en la ...

by Pello Altadill 08/16/2013 17:06:58 - 276 hits

More »

Un vistazo a Backbone

Backbone es un framework MVC de javascript para clientes web que facilita el desarrollo de aplicaciones de una sola página. El hecho de aplicar MVC permite separar los datos de la presentación y Backbone lo hace sin invadir la página y con una serie de funciones que permiten la persistencia de datos en el servidor. Dicho de otro modo, podemos hacer páginas web que man...

by Pello Altadill 08/16/2013 01:37:50 - 388 hits

More »

El ciclo de vida de una Activity en Android

Android tiene una forma peculiar de gestionar las aplicaciones que choca un poco con los sistemas operativos tradicionales. Pese a estar montado en un linux con el kernel 2.6, Android no tiene por costumbre matar las aplicaciones cuando las cerramos. La clave está en que igual lo hace o igual no, según las necesidades o lo que Android considere oportuno. La cosa es que no hay que empeñarse en tener un botón para matar la aplicación, oficialmente no se recomienda y se todo se resume a un tranqui...

by Pello Altadill 08/15/2013 13:55:06 - 852 hits

More »

Callbacks y funciones asíncronas, el estilo Node.js

El estilo nodejs Yo pensaba que sabía -algo- de javascript hasta que descubrí Node.js :P. En fin, espero ser siempre un aprendiz. Conforme te vas asomando a nuevas tecnologías tratas de hacer las cosas correctamente y como recién llegado aplicas lo de donde fueres haz lo que vieres. ¿Existe algún documento con las convenciones de Node.js? Sí, Node.js tiene una guía de estilo aunque no e...

by Pello Altadill 08/14/2013 22:08:41 - 909 hits

More »

Intents con parámetros y startActivityForResult

Cuando en Android queremos abrir una nueva pantalla o Activity se hace de una manera muy curiosa: se crea un Intent. Los Intent son eso, intentos. No garantizan que el resultado vaya a ser el correcto ni si quiera que alguien vaya a responder, y es que los intents se pueden usar tanto para abrir Activities como para solicitar cualquier cosa (iniciar una llamada, mandar un mensaje, etc... ). Con los intents en definitiva se llama a componentes de cualquier tipo. Pueden ser internos de la propia a...

by Pello Altadill 08/14/2013 12:57:24 - 540 hits

More »

Ejemplo de IndexedDB la BD de HTML5

HTML5 trae un montón de nuevas posibilidades al navegador. Se ha hablado mucho del formato de vídeo, del canvas, los websockets, de los nuevos controles de formulario pero a mí en particular me ha interesado especialmente aquello de una BD en el cliente. Es un tema que no está tan documentado como el resto y que en muchos libros de HTML5 o ni se menciona o se hace de pasada. Y lo que es peor, hay información en blogs pero a nada que esté desfasada los ejemplos no funcionan como la llamada a...

by Pello Altadill 08/13/2013 22:35:53 - 1278 hits

More »