Buscar en xnoccio
Archivos del autor
Viafirma entra en producción en la Fundación Tripartita
En VIAVANSI estamos de enhorabuena, ayer lunes 16/03/2009 entró en producción la Aplicación de gestión de las Acciones formativas de las empresas, de la Fundación Tripartita para la Formación en el Empleo (antiguo FORCEM). En esta institución han escogido Viafirma para introducir las funcionalidades de autenticación con certificados digitales con multitud de CA’s como DNI electrónico, FNMT, IZENPE, Camerfirma, ANCERT, Firma Profesional, etc.
Implementando una caché sencilla de objetos con Ehcache
Reciéntemente he estado revisando la arquitectura técnica de un proyecto Java EE que estaba teniendo serios problemas de escalabilidad. En Desarrollo todo iba como un tiro, pero con un número importante pero no escandaloso de registros (apenas 100.000) nos encontrábamos con tiempos de respuesta de algunas de las operaciones online que se podían ir a los 5 minutos. Obviamente esos tiempos no son admisibles para una operación web, por lo que urgía detectar fuentes de problemas y optimizar los procesos.
Realmente no había ninguna parte del código culpable al 100%, sino que la funcionalidad implementada, excesivamente flexible para el usuario, le permitía a éste realizar búsquedas y operaciones que finalmente implicaban una sucesión de consultas, filtrados, operaciones de unión/intersección de listas enormes, persistencia…
Para muchas de las listas que se manejaban, se podía garantizar su invariabilidad en un tiempo elevado. Datos, por ejemplo, relativos a provincias. Por ello daba la sensación de que implementar una caché de estas listas, y sobre todo de los resultados finales después de las mencionadas operaciones de unión/intersección, etc., podría ser oportuno. Es cierto que Hibernate permite caché de resultados (y de hecho utiliza Ehcache), pero en este caso hablamos de resultados post-procesados, por lo que no sería suficiente.
Cachear objetos en una aplicación Java EE es algo básicamente trivial: siempre disponemos de la opción de ubicar el objeto en contexto de aplicación (ServletContext) y recuperarlo cuando queramos. Sin embargo esta aproximación no deja de ser algo “de juguete”. Decidimos utilizar Ehcache en primer lugar porque sabíamos que Hibernate sacaba un buen provecho de él, pero sobre todo porque, con un desarrollo extremadamente sencillo, obtenemos importantes ventajas funcionales como:
- Gestión de caducidad del contenido. Pasado un tiempo determinado, la caché elimina el objeto cacheado y comienza a devolver NULL a las peticiones posteriores. Nos elimina la responsabilidad de persistir el tiempo de vida de un objeto cacheado.
- Configuración del máximo número de objetos a cachear en memoria. Podemos dimensionar la cantidad de objetos que deseamos cachear en memoria. Ehcache se encarga de serializar a disco todo lo que le sobra, y recuperarlo cuando sea necesario. Ni que decir tiene que todos los objetos a cachear deberán ser serializables.
- Posibilidad de despliegue en cluster.
- Eliminación de la caché durante el shutdown del servidor de aplicaciones.
- ¡No reinventar la rueda!
Al final desarrollamos una sencilla clase tipo Manager, implementando el patrón Singleton, que interactúa con Ehcache. Y en determinadas zonas de la aplicación, invocar a la cache para recuperar los objetos que anteriormente se generaban online.
Paso a poner el código, que al final sin chicha esto se queda en nada
Eso sí, me gustaría recalcar que el proceso de 5 minutos al final, con un poco de cariño, ha pasado a responder en menos de 10 segundos. Una ganancia de un 3000%…
/*
* File: CacheUtil.java
*
* Created on march 2009
*
*
* Copyright 2006-2029 Javier Echeverría Usúa (javieu at gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.viavansi.framework.core.cache;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.viavansi.framework.core.persistencia.servicios.excepciones.ExcepcionServicio;
/**
* @author Javier Echeverria Usua (javieu at gmail.com)
* @author Felix Garcia Borrego (borrego at gmail.com)
* @author Alexis Castilla Armero (pencerval at gmail.com)
*/
public class CacheUtil {
public Object getCachedObject(String key) throws Exception{
if(minutosVidaDefault == 0)
minutosVidaDefault = MINUTOS_DEFAULT;
return getCachedObject(key, minutosVidaDefault);
}
public void putCachedObject(String key, Object info) throws Exception{
if(minutosVidaDefault == 0)
minutosVidaDefault = MINUTOS_DEFAULT;
putCachedObject(key, info, minutosVidaDefault);
}
public Object getCachedObject(String key, int minutosCache) throws Exception{
Cache cacheCustodia = getInstance(minutosCache);
Element element = cacheCustodia.get(key);
if(element != null){
return cacheCustodia.get(key).getValue();
}
else{
return null;
}
}
public void putCachedObject(String key, Object info, int minutosCache) throws Exception{
Cache cacheCustodia = getInstance(minutosCache);
cacheCustodia.put(new Element(key,info));
}
private Cache getInstance(int minutosCache) {
Cache cache = null;
//Todavía no existe
int timeTolife = minutosCache * 60;
CacheManager manager = CacheManager.getInstance();
String nombreCache = "viavansiCachedInfo" + minutosCache;
if (manager.cacheExists(nombreCache)) {
cache = manager.getCache(nombreCache);
} else {
// Configuramos el apagado en caso de Error de la JVM o parada inesperada.
System.setProperty("net.sf.ehcache.enableShutdownHook", "true");
manager.addCache(new Cache(nombreCache, 100, true, false, timeTolife, timeTolife));
cache = manager.getCache(nombreCache);
}
return cache;
}
public static void shutDown() {
CacheManager.getInstance().shutdown();
}
private int MINUTOS_DEFAULT = 60;
private static int minutosVidaDefault = 0;
protected CacheUtil(int minutosVida) {
minutosVidaDefault = minutosVida;
}
public static void init(int minutosVida) {
minutosVidaDefault = minutosVida;
}
/*
* Constructor y accesores
*/
// Patrón Singleton
private static CacheUtil singleton;
//Instancia de Commons Logging
private Log log = LogFactory.getFactory().getInstance(this.getClass().getName());
/**
* private constructor (solo una instancia).
* @return AmbitoBO
*/
protected CacheUtil() throws ExcepcionServicio {
super();
log.debug("Creando nueva instancia de CacheUtil");
}
/**
* Devuelve instancia activa de AmbitoBO.
* Típico método de implementación de patrón singleton
* @return AmbitoBO
* @throws ExcepcionServicio
*/
public static CacheUtil getCurrentInstance() throws ExcepcionServicio {
if (singleton == null) {
try {
singleton = new CacheUtil();
} catch (ExcepcionServicio e) {
throw e;
}
}
return singleton;
}
}
Un saludo a todos, y poned una caché en vuestros corazones
Feliz Navidad!
Desde VIAVANSI, los redactores de Xnoccio os deseamos felices fiestas y que para el 2009 todo vaya bien o mejor. Gracias por vuestra fidelidad!
Problemas entre Maven y Trend Micro InterScan Web Security Suite
Este post no pretende ser más que una ayuda en castellano (encontrable vía Google) para aquellos que se encuentren con este problema en el futuro, ya que hemos encontrado bastantes referencias, pero pocas respuestas.
Los antecedentes
Nos encontrábamos en las instalaciones de un cliente, en un equipo Windows XP al cual le habíamos montado un kit de desarrollo completo: Eclipse (con diversos plugins), Maven, JDK, Tomcat’s de diversas versiones, etc., que tenía que integrarse con Hudson. En ese momento estábamos probando Maven sobre un sencillo proyecto de ejemplo; Maven debía descargar de un repositorio de librerías Artifactory recién descargado. Pero nos encontramos con efectos bastante raros:
- Al hacer un ‘mvn eclipse:eclipse’ en consola, observábamos que todos los JAR’s descargados daban un error de verificación de checksum. Es decir, parecía ser que el contenido del JAR descargado no era exactamente el esperado. Y además no conseguíamos cargarnos la librería jline, una de las dependencias de las librerías de Plexus. Raro raro, porque nunca habíamos visto ese error. ¿Estaba pasando algo en algún repositorio público?
- Al hacer un’mvn clean’, algo mucho más raro todavía. Veíamos un log extrañísimo de repente saltaba un applet en pantalla que nos pedía confirmación de una operación. ¡Este plugin Maven nuevo!
Las pesquisas
Evidentemente aquí hay algo raro. En el log Maven aparecen mensajes que no habíamos visto hasta ahora:
Downloading: http://sanisidro:8080/artifactory/public/org/apache/maven/shared/ma
ven-shared-io/1.1/maven-shared-io-1.1.jar
116K downloaded
[WARNING] *** CHECKSUM FAILED - Checksum failed on download: local = 'e67415a960
00a3110c7834caa325d965022491f6'; remote = '02e1d57be05ecac7dbe56a3c73b113e98f222
40f' - RETRYING
Downloading: http://sanisidro:8080/artifactory/public/org/apache/maven/shared/ma
ven-shared-io/1.1/maven-shared-io-1.1.jar
116K downloaded
[WARNING] *** CHECKSUM FAILED - Checksum failed on download: local = 'e67415a960
00a3110c7834caa325d965022491f6'; remote = '02e1d57be05ecac7dbe56a3c73b113e98f222
40f' - IGNORING
[INFO] [clean:clean]
Current policy properties:
mmc.sess_pe_act.block_unsigned: false
window.num_max: 5
jscan.sess_applet_act.sig_trusted: pass
file.destructive.state: disabled
jscan.sess_applet_act.block_all: false
window.num_limited: true
jscan.sess_applet_act.unsigned: instrument
mmc.sess_pe_act.action: validate
jscan.session.daemon_protocol: http
file.read.state: disabled
mmc.sess_pe_act.block_invalid: true
mmc.sess_pe_act.block_blacklisted: false
net.bind_enable: false
jscan.session.policyname: TU1DIERlZmF1bHQgUG9saWN5
mmc.sess_cab_act.block_unsigned: false
file.nondestructive.state: disabled
jscan.session.origin_uri: http://repo1.maven.org/maven2/org/apache/maven
/shared/file-management/1.2/file-management-1.2.jar
mmc.sess_cab_act.action: validate
net.connect_other: false
jscan.session.user_ipaddr: 127.0.0.1
jscan.sess_applet_act.sig_invalid: block
mmc.sess_cab_act.block_invalid: true
thread.thread_num_max: 8
jscan.sess_applet_act.sig_blacklisted: block
net.connect_src: true
thread.thread_num_limited: true
jscan.sess_applet_act.stub_out_blocked_applet: true
mmc.sess_cab_act.block_blacklisted: true
jscan.session.user_name: 127.0.0.1
thread.threadgroup_create: false
file.write.state: disabled
-->> returning Frame NULL
BaseDialog: owner frame is a java.awt.Frame
Empezamos a pensar. Tras unos minutos de desconcierto, eso de jscan huele a antivirus. A ver si está haciendo algo, modificando los JAR’s al descargarlos, modificando alguna Java Policy, modificando la JDK, o incluso interactuando con las políticas de seguridad en runtime… efectivamente, buscando en Google nos lleva a comprobar que el culpable parece ser el antivirus de Trend Micro. Debe estar colocando el applet Java como medida de seguridad, interceptando el código original. El antivirus ha debido pensar que el JAR es un applet y, como hace operaciones de disco (un ‘mvn clean’ debe borrar ficheros), pide permiso. Pero, ¿qué y cómo lo está haciendo? Realizamos unas cuantas tareas:
- Paramos todos los servicios del antivirus. Probamos, sigue fallando. Este antivirus es un poco retorcido, ha debido modificar la JVM o alguna Java Policy.
- Restauramos la JVM, nos aseguramos de estar utilizando lo mismo. Sigue fallando, con el antivirus parado… ¿qué pasa aquí? ¿Dónde está la coleta de este Sansón de la seguridad?
- Probamos el applet de firma de Viafirma, que tampoco funciona. En la Java console observamos un error de un paquete com.trend (si al menos funcionara bien!)… El error era “Exception at com.trend.iwss.jscan.appscan.runtime …”. Nos bajamos el JAR de firma, lo descomprimimos y ¡voilá! Hay un buen conjunto de paquetes nuevos dentro de JAR. El antivirus modifica los JAR’s, lo cual explica todo: el misterioso applet del mvn clean, la rotura del applet de viafirma, los fallos de checksum… pero ¡el antivirus está apagado! ¿Cómo lo hace?
Las conclusiones
Si el antivirus en local no es culpable, debe haber un antivirus a nivel de red, junto al proxy. Efectivamente. El cliente, que por fortuna es técnico y de los que programan, no de los que sólo hablan, nos confirma que en muchas ocasiones ha tenido que utilizar otro proxy para descargarse JAR’s. El invento enemigo de los JAR’s no afecta sólo a Maven, obviamente, sino a cualquier JAR descargado por un proxy que disponga de este mecanismo de seguridad, y que realice determinadas operaciones. De hecho la librería JLine era parada por este producto llamado “Trend Micro InterScan Web Security Suite” que, de hecho, publicita este servicio tan majo y maligno a la vez.
Así que si en algún momento os encontráis este tipo de errores tan extraños, ya tenéis otra posibilidad latente.
El epílogo
Nos cambiamos de proxy y todo fue bien, previa limpieza del repositorio de librerías Maven.
Implementación de la fórmula Haversine en Java
El algoritmo Haversine sirve para calcular la distancia entre dos puntos de los que conocemos su longitud y latitud. A continuación incluimos un método Java que implementa esta fórmula devolviendo la distancia en metros:
private static int calculateDistanceByHaversineFormula(double lon1, double lat1,
double lon2, double lat2) {
double earthRadius = 6371; // km
lat1 = Math.toRadians(lat1);
lon1 = Math.toRadians(lon1);
lat2 = Math.toRadians(lat2);
lon2 = Math.toRadians(lon2);
double dlon = (lon2 – lon1);
double dlat = (lat2 – lat1);
double sinlat = Math.sin(dlat / 2);
double sinlon = Math.sin(dlon / 2);
double a = (sinlat * sinlat) + Math.cos(lat1)*Math.cos(lat2)*(sinlon*sinlon);
double c = 2 * Math.asin (Math.min(1.0, Math.sqrt(a)));
double distanceInMeters = earthRadius * c * 1000;
return (int)distanceInMeters;
}
En nuestro caso ha sido utilizado para evaluar la distancia a un establecimiento determinado desde nuestra posición actual (calculada mediante GPS).
Leyendo un feed OpenSearch con código Java
De forma muy resumida, OpenSearch es una colección de formatos abiertos y estándares desarrollados por A9 (Amazon), que persiguen resolver 2 escenarios principalmente:
- Caso 1: Permitir a una aplicación publicar de una forma estándar resultados de búsqueda; estos resultados pueden ser consumidos posteriormente por una aplicación cliente. Se basa en un metamodelo estandarizado publicado bajo una fuente de sindicación estándar como RSS o Atom. Podemos ver un ejemplo de resultado de búsqueda en formato OpenSearch en esta URL de indeed.com.
- Caso 2: Describir (autodescribir) servicios de búsqueda. Es lo que utiliza por ejemplo Firefox 3 para ofrecernos búsquedas inteligentes.
En este post vamos a describir cómo leer resultados de búsqueda en formato OpenSearch (caso 1). Para el caso 2, recomendamos la lectura de un post de 11870.com que describe a la perfección cómo describir nuestro buscador.
Si nos fijamos en el código fuente de respuesta de la URL comentada de indeed, veremos que en este caso se está devolviendo sobre RSS una información general sobre la búsqueda más un conjunto de resultados de búsqueda (items), los cuales pueden ser incluso geolocalizados.
En Java, este RSS (o Atom) podría ser leído con cualquier intérprete de XML, o mejor con alguna librería específica de este tipo de feeds, como Rome o Apache Abdera, o mejor aún, con librerías específicas para OpenSearch. En nuestro caso, debíamos leer la respuesta del API de 11870.com, dentro de un proyecto en el cual deseábamos proponer establecimientos propuestos por los usuarios que estén cercanos a nuestra localización.
A este respecto, cuando he hecho la búsqueda de librerías Java, personal he tenido una sensación agridulce. Si bien los desarrolladores Java solemos ser unos verdaderos privilegiados en cuanto a lo que se refiere a disposición de API’s, en ciertos casos relacionados con web semántica o API’s de web 2.0 tengo la sensación de que otras arquitecturas de desarrollo como PHP, Python o RoR a veces tienen cierta ventaja. En el caso de Java todo son versiones de incubadora, 0.X, etc.
En el caso de librerías Java, una rápida búsqueda nos llevó a decidirnos entre Rome (Sun) y Apache Abdera, escogiendo este último por disponer de mejores ejemplos de los que partir. Además dentro de los committers de Abdera está el supercrack David Calavera, desarrollador de la omnipresente 11870.com.
A continuación incluiremos unos pequeños recortes de código que muestran como leer la respuesta OpenSearch mediante Abdera. En primer lugar, necesitaremos disponer de las librerías. Para ello (en el caso de Maven) incluiremos estas dependencias en nuestro pom.xml:
<dependency>
<groupId>org.apache.abdera</groupId>
<artifactId>abdera-client</artifactId>
<version>0.4.0-incubating</version>
</dependency>
<dependency>
<groupId>org.apache.abdera</groupId>
<artifactId>abdera-extensions-opensearch</artifactId>
<version>0.4.0-incubating</version>
</dependency>
Para poder resolver estas dependencias incluiremos los repositorio Incubating y Snapshot de Apache dentro de <repositories>:
<repository>
<id>apache-incubating</id>
<name>Apache Incubating Repository</name>
<url>http://people.apache.org/repo/m2-incubating-repository/</url>
</repository>
<repository>
<id>apache-snapshots</id>
<name>Apache Snapshot Repository</name>
<url>http://people.apache.org/repo/m2-snapshot-repository/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>
Dado una dirección URL (String urlQuery) donde esté publicada una consulta que responde OpenSearch, podremos invocarla con el siguente código:
Abdera abdera = new Abdera();
Parser parser = abdera.getParser();
URL url = new URL(urlQuery);
Document<Feed> doc = parser.parse(url.openStream(), urlQuery);
Feed feed = doc.getRoot();
Podemos recuperar ciertas propiedades de la respuesta de OpenSearch:
IntegerElement totalResults = feed.getExtension(OpenSearchConstants.TOTAL_RESULTS);
int resultados = totalResults.getValue();
Del mismo modo se pueden recuperar datos como el número de items por página (OpenSearchConstants.ITEMS_PER_PAGE) o el índice inicial de la respuesta, útil cuando hay paginación (OpenSearchConstants.START_INDEX. Es decir, podemos obtener datos OpenSearch del feed mediante feed.getExtension().
A continuación mostramos cómo iterar los items de respuesta del feed:
for (Entry entry : feed.getEntries()) {
System.out.println(“Title: “+entry.getTitle());
System.out.println(“Summary: “+entry.getSummary());
System.out.println(“Id: “+entry.getId().toString());
System.out.println(“Id: “+entry.getId().toString());
}
También podemos evaluar para cada item (resultado de búsqueda) el valor de extensiones a OpenSearch. Por ejemplo, podemos pretender recuperar los datos de geolocalización en formato GeoRss. Para ello utilizaríamos un código como el que sigue:
QName qnameWhere = new QName(“http://www.georss.org/georss/10″,”where”, “georss”);
Element where = entry.getExtension(qnameWhere);
try {
String geoPos = where.getFirstChild().getFirstChild()
.getText();
String[] posicion = geoPos.split(” “);
if (posicion.length == 2) {
System.out.println(“latitud: “+posicion[0]);
System.out.println(“longitud: “+posicion[1]);
}
} catch (Exception e) {
e.printStackTrace();
}
Es decir, podemos recuperar el valor de un parámetro de una extensión invocando a entry.getExtension, pasando como parámetro un objeto de tipo QName, instanciado como indicamos en el código anterior.
En definitiva, hemos hecho una breve introducción a OpenSearch y mostrado código de ejemplo para interactuar con una respuesta OpenSearch mediante Apache Abdera.
Programando para iPhone
A nivel personal he comenzado a colaborar en el blog Actualidad iPhone con una serie de artículos de iniciación al desarrollo de aplicaciones nativas y webapps para iPhone. No tendrán el detalle técnico que suele perseguir este blog, pero al menos puede servir de punto de partida para los lectores que quieran empezar desde cero a hacer unos pinitos con el ¿mejor? gadget de Apple…
¿Quieres trabajar en VIAVANSI?
En VIAVANSI seguimos buscando técnicos que encajen en nuestro grupo de trabajo, y hemos pensando que probablemente los lectores de nuestro blog sean muy adecuados para nosotros. ¿Qué esperamos de nuestros nuevos compañeros?
- Si saben Java, estupendo.
- Si tienen experiencia en los entornos y herramientas de la Junta de Andalucía, mejor.
- Si además entienden los posts técnicos de este blog, has oído hablar de Seam, etc., entonces la repera
Pero sobre todo esperamos que los nuevos compis encajen en este gran grupo humano. No nos entendáis mal, no esperamos que nadie venga a la entrevista disfrazado de Darth Vader
Pero sí que compartan nuestra pasión por la tecnología y por hacer las cosas bien.
Los candidatos podéis enviarnos vuestro CV a rrhh @ viavansi.com
Gracias!
Servicio técnico Apple iPhone: indefensión para el cliente
Esto es un post que se sale un poco de la línea tradicional de este blog, pero quiero aprovechar este medio para realizar un poco de “denuncia social” de algo que me ha pasado y que es absolutamente injusto.
Desde julio dispongo de un contrato iPhone 3G con Movistar. Esto significa 24 meses de permanencia, con una tarifa plana de datos 3G que sólo puedes utilizar desde el iPhone.
El pasado sábado día 11/10/08 observé que, mientras lo utilizaba, el iPhone comenzaba a mostrar fallos extraños, como que el brillo de la pantalla se bajaba automáticamente, la vibración se activaba y desactivaba sólo, etc. Probé varias opciones: apagar y encender, restaurar una copia de seguridad, etc., sin resultados, por lo que decidí llevarlo a reparar a una tienda Movistar (República Argentina 15 de Sevilla) que a su vez lo envió a Apple con fecha 14/10/2008.
Hoy, con fecha 23/10/2008 recibo el teléfono SIN REPARAR, y una indicación de Apple que dice que mi iPhone tiene daños internos “debido a que se han vertido líquidos sobre él o ha sido sumergido en líquido”.
Doy mi palabra de que bajo ningún concepto mi teléfono ha sufrido dicho trato. Además, este teléfono ha estado continuamente protegido por una funda Zagg Invisible Shield tanto en la pantalla como en la zona frontal, y con un ‘calcetín’ protector por encima, y lo cuidaba al extremo de la paranoia, como observo que hacen la mayoría de los afortunados poseedores de un teléfono como éste. No sé si el teléfono tendría realmente humedad o no cuando llegó al AppleCare Service de Cork, Irland… pero como si tenía el Nilo dentro, no ha sido mi culpa o responsabilidad. Hay muchísimas causas no aplicables al poseedor del teléfono por las que un terminal puede disponer de humedad en su interior, por ejemplo, por fallos de fábrica en la estanqueidad.
El caso es que en este tipo de situaciones se da una situación tremenda de indefensión. Lo que dicte el servicio técnico se convierte en verdad absoluta, y sin derecho a réplica. Fijaos por ejemplo en el caso de un pobre poseedor de un teléfono al que no se lo quisieron arreglar “por instalar software ajeno a terceros”, y lo que había instalado era ¡un tono!
http://es.engadget.com/2008/01/11/apple-niega-el-soporte-a-un-usuario-que-cambio-el-tono-de-llamad/
¿Y ahora qué?
Y para redondear la desgracia, Movistar no se hace cargo de nada, no sabe no contesta, pero desde luego, se remite a la permanencia de 24 meses por un servicio que no puede darme, como es una tarifa plana asociada a un terminal iPhone 3G que no funciona por causas ajenas a mi voluntad y responsabilidad.
A falta de poder hacer nada con esto, salvo intentar reclamar por las pobres vías que nuestra sociedad nos da, al menos puedo contar a nuestros lectores mi caso, para que lo tengan en cuenta si están pensando en adquirir un iPhone y encima con Movistar.
Actualización: después de un segundo envío a Apple, han pasado de mí e insisten con lo de que se ha mojado. Dado que yo no lo he mojado, empiezo a pensar en el impacto de un día de niebla el mismo día que se rompió… sobre todo mirando esto, que el iPhone se muere con el clima húmedo de Bélgica… Así que me sigo sintiendo un poco robado. He pasado a la última opción, abrirlo y ver qué pasa… una vez que hemos perdido la garantía, qué le vamos a hacer. Eso sí, como se recupere, Cydia, jailbreak y de todo. Leña al mono. Y si no se recupera, esa es la gracia: Movistar me “está obligando” a darme d baja, porque no existe la opción de volver a comprar otro (sería otro alta y otro contrato)… y me sale más barato pagar la indemnización.
Actualización 2: Arreglado abriéndolo! Efectivamente tenía algo de líquido pegajoso haciendo contactos, con lo que algo de razón tenían en Apple… claro que también decían que era irreparable, y en media hora el iPhone está como nuevo. Algo de razón tenía yo en que NO lo había mojado, y efectivamente… había sido (mucho ojo para los que os penséis en ponerlas) una filtración del líquido adherente de las fundas Invisible Shield de Zagg…
Formul@ 2.0
Formul@ (léase Formula) es un software desarrollado por VIAVANSI (cuyo desarrollo finalizó en 2007), que permite diseñar visualmente (mediante una interfaz Ajax con funcionalidades de drag&drop) formularios dinámicos que posteriormente pueden ser utilizados remotamente por otras aplicaciones. Ello es debido a que la necesidad de gestión visual de “dynamic forms” es cada vez más común y recurrente en multitud de proyectos. ¿En cuántos sistemas de información existe el requisito de disponer de formularios de entrada de datos, y cuánto esfuerzo de desarrollo y mantenimiento evolutivo implica?
Nuestra idea consistió en desarrollar un componente específico especializado que se responsabilizase de esta tarea dentro de una arquitectura de servicios, del mismo modo que se usa un servidor de base de datos para persistir información o se usa un servidor SMTP para enviar un email.
Básicamente y a grandes rasgos, Formul@ se encarga de las siguientes tareas:
- Definición visual de formularios complejos.
- Almacenamiento de la definición en un metamodelo XML.
- Rendeo de los formularios bajo demanda de aplicaciones cliente. Nótese que al basarse en una definición modelada en XML, del mismo modo que un formulario se rendea en web, podría rendearse en una aplicación de escritorio, en un teléfono móvil, etc… Un sólo trabajo de definición, múltiples salidas para el formulario.
Te invitamos a que pruebes la demo del diseñador de formularios Formul@.
A nivel técnico Formul@, que inicialmente surgió como desarrollo interno de I+D, hace uso de las últimas tecnologías disponibles en el mundo Java como son Java Server Faces (JSF), Java Persistent Api (JPA, Ajax, Maven, Web services usando JSR 181, XSL-FO, etc.
A nivel funcional, si probáis la demo del diseñador podréis observar que pueden crear varias páginas, dentro de las páginas bloques de varios tipos, dentro de éstos contenedores para maquetar, dentro de los contenedores campos de diversos tipos… Y luego las aplicaciones cliente pueden usar y controlar el comportamiento de los formularios a través de un API.
Formul@ ha sido desarrollada para la Junta de Andalucía, por lo que está liberada como software libre dentro del Repositorio de Software Libre de la Junta de Andalucía.
Actualmente estamos trabajando para la Junta con el objetivo de incluir muchas mejoras en el motor. ¡Pon Formul@ en tu vida!
PD: Formul@ no sólo se ha utilizado en varios proyectos de desarrollo de VIAVANSI, como no podría ser de otra forma… por ejemplo, otras empresas (como nuestros colegas de Guadaltel, ahí va una referencia gratuita en agradecimiento por el paintball) lo han utilizado (dentro del ámbito local andaluz) como motor visual de formularios dinámicos en la Oficina Virtual del Ayuntamiento de Córdoba, en el sistema de Comunicaciones Internas eCO de la Junta de Andalucía, en el ambicioso Sistema de Gestión Global del Gasto (G3) de la Junta de Andalucía, etc.

