Para acceder a los objetos de una colección en una plantilla de Handlebars tienes que pasar dichos objetos como un parámetro a la función template. Si utilizas Backbone y tu colección de objetos es una colección de modelos, puedes utilizar la función toJSON para convertirlos en objetos javascript y que puedan ser interpretados por Handlebars.

Supongamos que tenemos los siguientes objetos (modelos)

app.models.Equipo = Backbone.Model.extend({

    initialize: function () {

    },

    sync: function (method, model, options) {
    if (method === 'read') {
        app.adapters.equipos.findById(parseInt(this.id)).done(function (data) {
            options.success(data)
        })
    }
    }
})

app.models.EquipoCollection = Backbone.Collection.extend({

    model: app.models.Equipo,

    sync: function (method, model, options) {
    if (method === 'read') {
        app.adapters.equipos.findAll().done(function(data){
            options.success(data)
        })
    }
    }
})

y nuestra plantilla es la siguiente

    <div class="row">
        {{#each equipos}}
        <div class="col-6">
            <a href="equipos/#{{name}}" class="thumbnail text-center">
                <img src="{{logoUrl}}"/>
            </a>
        </div>
        {{/each}}
    </div>

Entonces para pasar nuestros objetos a la plantilla, lo haríamos de la siguiente manera

app.views.EquiposListView = Backbone.View.extend({
    initialize: function(){
        this.equipos = new app.models.EquipoCollection()
        this.equipos.on('reset', this.render, this)
        this.equipos.fetch({reset: true})
    },

    render: function(){
        this.$el.html(this.template({equipos: this.equipos.toJSON()}))
        return this
    }

})

Notesé el uso de la función toJSON

Fuentes:
http://stackoverflow.com/questions/12439471/rendering-handlebars-template-with-backbone
http://stackoverflow.com/questions/14170298/how-to-access-backbone-model-properties-in-a-handlebar-template

Anuncios

En un servicio REST (jax-rs) puedes enviar los parámetros de una petición de varias formas: en la URL (@QueryParam), en el cuerpo del mensaje con el encabezado “application/x-www-form-urlencoded” (@FormParam), como parte de la URL (@PathParam).

Pero que pasa si el cliente envía toda la información en el cuerpo del mensaje en formato JSON.
Por ejemplo:

    {
        "tipo":"URGENTE",
        "actores":[
        {
            "nombre":"Juan",
            "apellidos":"Peréz",
            "idEstado":null,
            "idMunicipio":null,
            "idColonia":null,
            "calle":"Calle 2",
            "numero":"155",
            "codigoPostal":"76800"
        }
        ],
        "demandados":[
        {
            "nombre":"María",
            "apellidos":"López",
            "idEstado":null,
            "idMunicipio":null,
            "idColonia":null,
            "calle":"Calle 4",
            "numero":"45",
            "codigoPostal":"76800"
        }
        ]
    }

Podríamos crear una clase que reflejará esta estructura, pero si solo nos interesa algún campo o la petición no tiene nada que ver con nuestro modelo, no parece la mejor opción.

En este caso, en nuestro modelo existiría una clase Actor y Demandado que comparten los mismos campos, por lo que podríamos usar la herencia.

    public class Parte {
        String id;
        String nombre;
        String apellidos;
        String idEstado;
        String idMunicipio;
        String idColonia;
        String calle;
        String numero;
        String codigoPostal;
        public Parte() {
        }
        //... getter's y setter's, métodos, etc.
    }
    public class Actor extends Parte{
        //... otras propiedades
        public Actor() {
        }
        //... otros métodos
    }
    public class Demandado extends Parte{
        //... otras propiedades
        public Actor() {
        }
        //... otros métodos
    }

en nuestro servicio REST (Apache CXF) podríamos deserializar el arreglo de Actores de la siguiente forma

    @Path("solicitar/")
    public String solicitar(String data){
        String response = null;
        try{
            ObjectMapper mapper=new ObjectMapper();
            mapper.configure(SerializationConfig.Feature.WRITE<em>DATES</em>AS<em>TIMESTAMPS, false);
            mapper.configure(Feature.FAIL</em>ON<em>UNKNOWN</em>PROPERTIES, false);
            Map<String, Object> map = mapper.readValue(data, new TypeReference<Map<String, Object>>(){});
            String tipo = (String) map.get("tipo");
            List
<Parte> actores = mapper.convertValue(map.get("actores"), new TypeReference
<List<Parte>>() {});
            //... registrar la solicitud
            response = mapper.writeValueAsString(actores);
        }catch(Exception e){
            String error = "Ocurrió un problema al hacer la solicitud";
            log.error(error, e);
            response = String.format("{\"response\":{\"status\": -1, \"data\": \"%s\"}}", error);
        }
        return response;
    }

Fuentes:
http://wiki.fasterxml.com/JacksonDataBinding
http://cxf.apache.org/docs/jax-rs-basics.html#JAX-RSBasics-DealingwithParameters

En datanucleus existe un mecanismo llamado attach/detach que sirve para acceder a las propiedades de los objetos fuera del contexto de una transacción. Esto es muy útil, por ejemplo, cuando estructuras tu aplicación en librerías o capas.

Supongamos que tenemos la siguiente clase

    @PersistenceCapable
    public class Audiencia {</p><pre><code>    @PrimaryKey
    @Persistent
    Integer id;
    @Persistent
    Juez juez;
    @Persistent
    Date inicio;
    @Persistent
    Date fin;
    @Persistent
    TipoAudiencia tipo;

    public Audiencia(){
    }

    public static List&lt;Audiencia&gt; getAudiencias(Integer idJuez) {
        List&lt;Audiencia&gt; audiencias;
        PersistenceManager pm = PMF.get().getPersistenceManager();
        Transaction tx = pm.currentTransaction();
        try{
            tx.begin();
            String filter = "juez.id == :idJuez";
            Query query = pm.newQuery(Audiencia.class, filter);
            audiencias = (List&lt;Audiencia&gt;) pm.detachCopyAll((List&lt;Audiencia&gt;)query.executeWithArray(idJuez));
            tx.commit();
        }finally{
            if(tx.isActive()){
                tx.rollback();
            }
            pm.close();
        }
        return audiencias;
    }

}
</code></pre><p>

cabe destacar que dentro del contexto de la transacción podríamos leer las propiedades Juez y TipoAudiencia, datanucleus cargaría los objetos relacionados de forma “lazy loading”. Pero si trataramos de leer alguna propiedad fuera de este contexto -es el caso cuando ejecutamos el método getAudiencias desde otra clase- está tendría el valor null. Datanucleus sólo hace el detach de las propiedades en el Default Fetch Group. Para poder utilizar las demás propiedades, podemos especificar un Fetch Group dinámico de la siguiente manera

    public static List getAudiencias(Integer idJuez, String[] fields) {
        List audiencias;
        PersistenceManager pm = PMF.get().getPersistenceManager();
        Transaction tx = pm.currentTransaction();
        try{
            tx.begin();
            FetchGroup fetchGroup = PMF.get().getFetchGroup(Audiencia.class, "fields");
            fetchGroup.addMembers(fields);
            pm.getFetchPlan().addGroup("fields");
            String filter = "juez.id == :idJuez";
            Query query = pm.newQuery(Audiencia.class, filter);
            audiencias = (List) pm.detachCopyAll((List)query.executeWithArray(idJuez));
            tx.commit();
        }finally{
            if(tx.isActive()){
                tx.rollback();
            }
            pm.close();
        }
        return audiencias;
    }

Fuentes:
http://www.datanucleus.org/products/accessplatform/jdo/fetchgroup.html
http://www.datanucleus.org/products/datanucleus/jdo/attachdetach.html
http://www.datanucleus.org/products/datanucleus/jdo/object
lifecycle.html

GWT – JSON dates

marzo 11, 2013

JSON no tiene un tipo de dato Date, así que cuando transfieres fechas mediante JSON debes convenir un formato de fecha -por ejemplo, yyyy-MM-dd’T’hh:mm:ss.SZ- Un ejemplo de fecha en este formato sería “2013-03-08T16:23:35.000+0000”.

Para facilitar un poco las cosas, decidí utilizar un Overlay Type para la representación de mi objeto y acceder a sus propiedades mediante getter’s y setter’s. Estos métodos realizan la conversión de cadena a fecha, y viceversa, con la ayuda de la clase DateTimeFormat.

    public class Audiencia extends JavaScriptObject {</p><pre><code>    private final static DateTimeFormat dateTimeFormat = DateTimeFormat.getFormat("yyyy-MM-dd'T'hh:mm:ss.SZ");

    public final native int getId()/*-{
        return this.id;
    }-*/;

    public final Date getInicio(){
        return dateTimeFormat.parseStrict(getInicioNative());
    };

    private final native String getInicioNative()/*-{
        return this.inicio;
    }-*/;

    public final Date getFin(){
        return dateTimeFormat.parseStrict(getFinNative());
    };

    private final native String getFinNative()/*-{
        return this.fin;
    }-*/;

    protected Audiencia() {
    }

    public static void getAudiencias(String idSala,
            final AsyncCallback&lt;Audiencia[]&gt; callback) {
        try {
            String queryParams = "?sala="+URL.encodeQueryString(idSala);
            RequestBuilder rb = new RequestBuilder(RequestBuilder.GET,
                    Consts.REST_AUDIENCIAS + queryParams);
            rb.sendRequest(null, new RequestCallback() {

                @Override
                public void onResponseReceived(Request request,
                        Response response) {
                    if(response.getStatusCode() == 200){
                        JavaScriptObject jso = JSON.decode(response.getText());
                        DSResponse ds = new DSResponse(JSOHelper.getAttributeAsJavaScriptObject(jso, "response"));
                        if(ds.getStatus() == 0){
                            Record[] records = ds.getData();
                            Audiencia[] audiencias = new Audiencia[records.length];
                            for(int i=0;i&lt;records.length;i++){
                                audiencias[i] = (Audiencia) records[i].getJsObj();
                            }
                            callback.onSuccess(audiencias);
                        }else{
                            callback.onFailure(new Exception(ds.getAttributeAsString("data")));
                        }
                    }else{
                        callback.onFailure(new Exception(response.getStatusText()));
                    }
                }

                @Override
                public void onError(Request request, Throwable exception) {
                    callback.onFailure(exception);
                }
            });
        } catch (Exception e) {
            callback.onFailure(e);
        }
    }

}
</code></pre><p>

Esto es necesario porque el método JSON.decode) crea el objeto Javascript con propiedades (inicio y fin) de tipo String.

Si tienes un ListGrid enlazado a un DataSource y quieres actualizar un registro mediante código, lo puedes hacer de la siguiente manera

</pre><p>IButton btnEliminar=new IButton("Eliminar");<br /> btnEliminar.addClickHandler(new ClickHandler() {<br /> <br /> @Override<br /> public void onClick(ClickEvent event) {<br /> final ListGridRecord empleado = grdEmpleados.getSelectedRecord();<br /> if(grdEmpleados.getSelectedRecord()!=null){<br /> SC.ask("Baja", "¿Dar de baja al empleado '"+empleado.getAttribute("nombre")+"' ?", new BooleanCallback() {<br /> <br /> @Override<br /> public void execute(Boolean eliminar) {<br /> if(eliminar){<br /> empleado.setAttribute("status", "BAJA");<br /> grdEmpleados.updateData(empleado);<br /> }<br /> }<br /> });<br /> }<br /> }<br /> });</p><pre><br />

En este ejemplo utilizamos un botón para dar de baja a un empleado, actualizando su propiedad status en vez de eliminar el registro.

Fuentes:

Changing the list grid values on runtime.

Un tipo de propiedad que encontramos comunmente en nuestros objetos es el tipo Boolean. Puede ser para describir si un registro esta activo o no, o para marcar una tarea como realizada, etc. En una base de datos no es común encontrar este tipo de dato para una columna. Normalmente lo representamos mediante un Number(‘0’ o ‘1’) o un Char (‘S’ o ‘N’). En nuestro caso utilizamos el Char.

Al utilizar Datanucleus con JDO para mapear la siguiente clase

@PersistenceCapable(table="TC_EMPLEADOS")
public class Empleado {
@PrimaryKey
@Persistent(column="NID")
Integer id;
@Persistent(column="SNOMBRE")
String nombre;
@Persistent(column="BACTIVO")
Boolean activo;
public Empleado() {
}

}

me arrojaba un error parecido al siguiente:

NucleusDatastoreException: Fail to convert to internal representation

El problema es que, por default, Datanucleus trata de mapear la propiedad “activo” a un valor númerico (‘0’ o ‘1’). Para mapear la propiedad a una cadena podemos hacer lo siguiente:

@PersistenceCapable(table="TC_EMPLEADOS")
public class Empleado {

@PrimaryKey
@Persistent(column="NID")
Integer id;

@Persistent(column="SNOMBRE")
String nombre;

@Persistent(column="BACTIVO")
String activo;

public Empleado() {
}

public Boolean getActiv0() {
   return "S".equals(activo);
}

public void setActivo(Boolean activo) {
   this.activo = activo?"S":"N";
}

}

Notesé que utilizamos el tipo String para la propiedad y Boolean para los métodos de acceso a la propiedad.

Fuentes:

http://turbomanage.wordpress.com/2009/12/04/persisting-enums-with-appengine-datastore/

En el diseño de bases de datos relacionales, se llama clave primaria a un campo o a una combinación de campos que identifica de forma única a cada fila de una tabla. No pueden haber dos filas en una tabla que tengan la misma clave primaria.
Un ejemplos de claves primarias es el ISBN (asociado a un libro).

Supongamos que tenemos una entidad Usuario que es identificada por 2 propiedades: id e idJuzgado. Para especificar la llave compuesta en Datanucleus lo haríamos de la siguiente manera:

@PersistenceCapable(objectIdClass=Usuario.ComposedIdKey.class)
public class Usuario {

public static class ComposedIdKey implements Serializable
{
    public Integer id;
    public String idJuzgado;

    public ComposedIdKey ()
    {
    }

    /**
     * Constructor accepting same input as generated by toString().
     */
    public ComposedIdKey(String value)
    {
        StringTokenizer token = new StringTokenizer (value, "::");
        token.nextToken();               // className
        this.id = Integer.parseInt(token.nextToken()); // field1
        this.idJuzgado = token.nextToken(); // field2
    }

    public boolean equals(Object obj)
    {
        if (obj == this)
        {
            return true;
        }
        if (!(obj instanceof ComposedIdKey))
        {
            return false;
        }
        ComposedIdKey c = (ComposedIdKey)obj;
        return id.equals(c.id) && idJuzgado.equals(c.idJuzgado);
    }

    public int hashCode ()
    {
        return this.id.hashCode() ^ this.idJuzgado.hashCode();
    }

    public String toString ()
    {
        // Give output expected by String constructor
        return this.getClass().getName() + "::"  + this.id + "::" + this.idJuzgado;
    }
}

@PrimaryKey
Integer id;
@PrimaryKey
String idJuzgado;
String nombre;
String apellidoPaterno;
String apellidoMaterno;

public Usuario() {
}

public Integer getId() {return id;}
public void setId(Integer id) {this.id = id;}
public String getNombre() {return nombre;}
public void setNombre(String nombre) {this.nombre = nombre;}
public String getApellidoPaterno() {return apellidoPaterno;}
public void setApellidoPaterno(String apellidoPaterno) {this.apellidoPaterno = apellidoPaterno;}
public String getApellidoMaterno() {return apellidoMaterno;}
public void setApellidoMaterno(String apellidoMaterno) {this.apellidoMaterno = apellidoMaterno;}
}

Notesé el uso de la clase Interna Usuario.ComposedIdKey en el parámetro de la anotación @PersistenceCapable y el uso de 2 anotaciones @PrimaryKey en las propiedades correspondientes.

Para realizar la consulta de un Objeto con una clave primaria compuesta debemos utilizar la sobrecarga del método getObjectById de la siguiente forma:


Usuario usuario=null;
 PersistenceManager pm = PMF.get().getPersistenceManager();
 Transaction tx = pm.currentTransaction();
 try{
 tx.begin();
 usuario = (Usuario) pm.getObjectById(new Usuario.ComposedIdKey(Usuario.ComposedIdKey.class.getName()+"::"+id+"::"+idJuzgado), false);
 tx.commit();
 }finally{
 if(tx.isActive()){
 tx.rollback();
 }
 pm.close();
 }

si tratas de utilizar el método getObjectById de la siguiente forma

pm.getObjectById(Usuario.class,new Usuario.ComposedIdKey(Usuario.ComposedIdKey.class.getName()+"::"+id+"::"+idJuzgado));

te arrojará una excepción parecida a la siguiente

javax.jdo.JDOUserException: Unable to create Object Identity for class “server.model.Usuario” since key is of an unsupported type (server.model.Usuario$ComposedIdKey

Fuentes:
http://www.datanucleus.org/products/datanucleus/jdo/primary_key.html
http://www.datanucleus.org/products/datanucleus/jdo/orm/compound_identity.html
http://es.wikipedia.org/wiki/Clave_primaria
http://book.javanb.com/using-and-understanding-java-data-objects/LiB0035.html