Buscar este blog

lunes, 22 de diciembre de 2014

Java: XSD to POJO

Se parte de un XSD y se generan las clases Java correspondientes.
Se empleará JAXB.

La herramienta que se usará es xjc, que viene instalada en el directorio \bin de los JDK. Si no se tiene esta ruta dentro del path, simplemente habrá que referenciarla desde una ventana de comandos.


Se necesita un fichero de binding para que se cree una clase por cada elemento del XSD, sino, se generará una única clase pública con clases internas.

Fichero jaxb-binding.xml:

<jaxb:bindings
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
    version="2.1">
    <jaxb:globalBindings localScoping="toplevel"/>
</jaxb:bindings>


Con esto, sólo hace falta tener el XSD que se quiera mapear, por ejemplo, el famoso employee.xsd:


<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:element name="employee" type="employee"/>

  <xs:complexType name="employee">
    <xs:sequence>
      <xs:element name="name" type="xs:string" minOccurs="0"/>
      <xs:element name="salary" type="xs:double"/>
      <xs:element name="designation" type="xs:string" minOccurs="0"/>
      <xs:element name="address" type="address" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute name="id" type="xs:int" use="required"/>
  </xs:complexType>

  <xs:complexType name="address">
    <xs:sequence>
      <xs:element name="city" type="xs:string" minOccurs="0"/>
      <xs:element name="line1" type="xs:string" minOccurs="0"/>
      <xs:element name="line2" type="xs:string" minOccurs="0"/>
      <xs:element name="state" type="xs:string" minOccurs="0"/>
      <xs:element name="zipcode" type="xs:long"/>
    </xs:sequence>
  </xs:complexType>
</xs:schema>


Finalmente, se lanza el comando:

xjc.exe -d . -p es.pruebas.jaxb -b jaxb-binding.xml employee.xsd


martes, 9 de diciembre de 2014

java.lang.NoSuchMethodException: org.objectweb.asm.MethodWriter.visitLabel(org.objectweb.asm.Label)

Seguramente estás usando JBOSS.

El problema es que se están pisando las clases de asm de JBOSS con las incluídas en el lib de la aplicación.

Solución

1) Eliminar que no haya ninguna dependencia de asm en el war. Se puede ver con el Dependency Hierarchy del pom o directamente en el war generado.
Por lo general estas librerías las mete Apache CXF, así que una solución es hacer la siguiente exclusión:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<dependency>
 <groupId>org.apache.cxf</groupId>
 <artifactId>cxf-rt-frontend-jaxws</artifactId>
 <exclusions>
  <exclusion>
   <artifactId>asm</artifactId>
   <groupId>asm</groupId>
  </exclusion>
 </exclusions>
</dependency>

2)Usar el asm de JBOSS.
Hay que incluir la dependencia del módulo asm.asm desde el jboss-deployment-structure (va en el META-INF):


1
2
3
4
5
6
7
<jboss-deployment-structure>
 <deployment>
  <dependencies>
   <module name="asm.asm" />  
  </dependencies>
 </deployment>
</jboss-deployment-structure> 


Hibernate proxy to real object - Hibernate proxy to java POJO

Objetivo

Convertir un objeto persistente, recuperado de base de datos con Hibernate, en un POJO java.
Los objetos Hibernate realmente son proxys que se utilizan, por ejemplo, para la inicialización de cargas vagas.
Cuando se tiene una lista dentro de un objeto de Hibernate, esta lista es un PersistentBag que, en el momento de acceder a ella por primera vez, accede a base de datos para cargarla.
En algunas ocasiones se necesita eliminar la "naturaleza de Hibernate" de un objeto, para quitar esos proxys y convertirlos en objetos reales. Así, a la hora de devolver un objeto en un servicio web o hacia la vista sería conveniente trabajar siempre con POJOs.

Solución

Crear un aspecto que intercepte las salidas de los DAOs y ponga a null los proxys no inicializados
En este código a los DAOs se les llama Fachada.

El aspecto inspecciona por reflexión el objeto devuelto. Revista todas sus propiedades y, si alguna no está inicializada (Hibernate.isInitialized) la setea a null.

Código fuente del aspecto:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import java.lang.reflect.Field;
import java.util.Collection;

import org.aspectj.lang.ProceedingJoinPoint;
import org.hibernate.Hibernate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Aspecto que elmina la naturaleza de hibernate de un objeto. Se ejectua
 * después del retorno de las fachadas e inspecciona los objetos devueltos
 * convirtiendo los proxys de Hibernate en null.
 *
 * @author Sisifo
 *
 */
public class EliminaHibernateProxysAspect {
    private final Logger logger = LoggerFactory.getLogger(getClass());

    public Object eliminarHibernateProxysAround(final ProceedingJoinPoint pjp) throws Throwable {
        final Object retVal = pjp.proceed();
        inicializarSiEsNecesario(retVal);
        return retVal;
    }

    @SuppressWarnings("rawtypes")
    private Object inicializarSiEsNecesario(Object object) {
        if (object == null) {
            return null;
        }

        if (!Hibernate.isInitialized(object)) {
            return null;
        } else {
            if (object instanceof Collection) {
                return inicializarColeccion((Collection) object);
            } else {
                return inicializarPropiedadesObjeto(object);
            }
        }

    }


    @SuppressWarnings("rawtypes")
    private Collection inicializarColeccion(Collection coleccion) {
        for (Object object : coleccion) {
            inicializarSiEsNecesario(object);
        }

        return coleccion;
    }

    private Object inicializarPropiedadesObjeto(Object object) {
        for (Field field : object.getClass().getDeclaredFields()) {
            if (fieldEsSusceptibleDeInicializarse(field)) {
                field.setAccessible(true);
                try {
                    field.set(object, inicializarSiEsNecesario(field.get(object)));
                } catch (final Exception e) {
                    logger.error("Se ha producido un error al acceder al campo {} del objeto {}", new Object[] { field,
                            object }, e);
                    throw new RuntimeException("Error al acceder a campo", e);
                }
            }
        }

        return object;
    }

    private boolean fieldEsSusceptibleDeInicializarse(final Field field) {
        if (Collection.class.isAssignableFrom(field.getType())) {
            return true;
        }

        if (!claseEsDeTipoBasico(field.getType()) && !clasePertenceALaEspecificiacionJava(field.getType())) {
            return true;
        }

        return false;
    }

    private boolean clasePertenceALaEspecificiacionJava(final Class<?> clase) {
        final String clasePropiedad = clase.getCanonicalName();
        if (clasePropiedad.startsWith("java.") || clasePropiedad.startsWith("javax.")) {
            return true;
        }
        return false;
    }

    private boolean claseEsDeTipoBasico(final Class<?> clase) {
        if (clase.isEnum() || clase.isPrimitive()) {
            return true;
        }
        return false;
    }
}

Fichero de cofiguración aop:


1
2
3
4
5
6
7
8
9
<bean id="eliminaHibernateProxysAspectImpl" class="es.sisifo.simplearchetype.persistencia.aop.EliminaHibernateProxysAspect"/>

<aop:config>
   <aop:pointcut id="fachadePointcut"     expression="execution(* es.sisifo..persistencia..*FacadeImpl.*(..))"/>

  <aop:aspect id="eliminaHibernateProxysAspect" ref="eliminaHibernateProxysAspectImpl">      
    <aop:around pointcut-ref="fachadePointcut" method="eliminarHibernateProxysAround"/>            
 </aop:aspect>           
</aop:config>

domingo, 30 de noviembre de 2014

Primeros pasos Microsoft Project 2010 - First steps Microsoft Project 2010

En este post se describen las tareas básicas para configurar un proyecto de MP 2007 y comenzar a introducir tareas.

Los pasos a seguir son los siguientes.

Configurar gestión de tareas
En las opciones generales del proyecto (File > Options) seleccionar schedule. Ahí hay que actualizar los siguientes campos:

  • New task created: Autoscheduled
  • Default task type: Fixed work


Con esto se consigue que las tareas se vayan organizando automáticamente y que la duración que se introduce sea siempre las horas que se estima que van a dura. De otro modo la duración se especificaría en días, independiente de la jornada laboral existente.


Configurar calendario
Con esto se introduce la jornada laboral del proyecto.
En la barra de tareas principal hay que ir a Project > Change Working Time



Una vez ahí se crea un nuevo calendario (si no se tuviera de proyectos anteriores) con la jornada laboral que se empleará.

Se asigna el nuevo horario en "Work Weeks" pulsando en defaults.


También se pueden añadir las vacaciones en la pestaña Exceptions.


Configurar inicio de proyecto
Con esto se indica cuándo va a comenzar el proyecto, y también se le asigna el calendario que se creó en el paso anterior.

En la barra de tareas principal hay que ir a Project > Project Information




Configurar vista de tareas
Por defecto, en la vista de Gantt Chart, se muestra la duración de la tarea, entre otras cosas. A la hora de planificar lo que suele interesar es introducir el trabajo (horas que va a llevar hacerla) y que MP calcule la duración (en función de los recursos asignados y la jornada laboral, cuántos días va a llevar trabajar esas horas).

Lo que habrá que hacer es borrar esa columna y añadir una de "Work".




Configuración de nivelado de recursos
En algún punto habrá que crear los recursos y asignárselos a cada tarea, incluyendo el tanto por ciento de dedicación al que van estar.

El siguiente paso ya sería generar la planificación en sí, en función de tareas y recursos. Para ello la opción más simple es empleando el "Level Resource" o "Level All".

Antes de esto lo mejor es configurar las opciones de nivelado. Para ello hay que ir a Resoruce > Leveling Options.



Aquí lo que suelo cambiar es:
  • Desmarcar la opción para permitir cambios de asignación en tareas.
  • Desmarcar la opción para permitir separación de tareas
También se puede cambiar el leveling order a ID only. En este caso a la hora de distribuir en el tiempo dos tareas para un mismo recurso se ejecutarán en el orden en el que se hayan introducido en la vista de Gantt.


Información adicional
Para más información sobre como gestionar la distribución de recursos se puede consultar la siguiente página: Simple Tips for Leveling Resources in MS Project

miércoles, 19 de noviembre de 2014

Apache Chemistry Cmis Workbench - proxy

Descubierto por Jacovo ;)

Objetivo
Lanzar el CMIS Workbench de Apache Chemistry configurado para que eacepte un proxy.

Cuando se lanza detrás de un proxy corporativo que requiere autenticación, el workbech no conecta con el gestor documental y se queda colgado.


Solución

Dentro del directorio del workbench, editar el archivo workbench.bat y sustituir la última línea por la siguiente:

start /B javaw -Dhttp.proxyHost=proxy.indra.es -Dhttp.proxyPort=8080 -Dhttp.proxyUser=usuariodelproxy -Dhttp.proxyPassword=passworddelproxy -Dhttp.nonProxyHosts=localhost -Dorg.apache.chemistry.opencmis.binding.webservices.jaxws.impl=sunjre -classpath ".;*" org.apache.chemistry.opencmis.workbench.Workbench