El tamaño máximo de un archivo que puedes almacenar en una USB (fat32) es de 2Gb (o 4Gb si estas utilizando LFS).

Si quieres copiar un archivo con un tamaño mayor, en linux, puedes hacerlo mediante el comando split, por ejemplo

split -b 2048 image.iso

que nos producirá una serie de archivos

image.isoaa
image.isoab
image.isoac
...

Después para juntarlos utilizamos el comando cat

cat image.iso* > ~/image.iso

El comando anterior no nos muestra un avance del progreso. Para ver el progreso podemos utilizar el comando pv, para instalarlo ejecuta sudo apt-get install pv y lo utilizas de la siguiente manera

cat image.iso* | pv -s $(du -cb image.iso* | grep total | awk '{print $1}') > ~/image.iso

Fuentes:
http://unix.stackexchange.com/questions/24630/whats-the-best-way-to-join-files-again-after-splitting-them
http://www.catonmat.net/blog/unix-utilities-pipe-viewer/
http://en.wikipedia.org/wiki/File_Allocation_Table#FAT32
http://unix.stackexchange.com/questions/41550/find-the-total-size-of-certain-files-within-a-directory-branch

Anuncios

Para la digitalización de documentos utilizamos escáneres que producen archivos TIFF, estos permiten almacenar varias imágenes en el mismo archivo. Estas imágenes se guardan en una base de datos para su posterior consulta.

Para poder desplegar estas imágenes en una aplicación web, necesitamos convertirlas a un formato estándar para la web (JPG, PNG ó GIF). Esto se puede lograr utilizando la librería image magick. Para usarla en Java existen 2 opciones: JMagick e im4java. Decidí utilizar im4java debido a los riesgos de usar JNI en una aplicación web (http://im4java.sourceforge.net/docs/faq.html)

Lo primero es agregar la dependencia de im4java a nuestro proyecto, archivo pom.xml si usas maven o agregar el jar a tu build path.

   <dependency>
      <groupId>org.im4java</groupId>
      <artifactId>im4java</artifactId>
      <version>1.4.0</version>
   </dependency>

Utilizamos un arreglo de bytes para cargar la imágen desde la base de datos y lo pasamos como un stream a la librería im4java para seleccionar la página que deseamos convertir al formato jpg.

    public byte[] getPagina(Integer pagina) throws Exception{
        byte[] imgPagina = null;
        byte[] imagen = loadImageFromDatabase();
        try{
        IMOperation op = new IMOperation();
        op.addImage(String.format("-[%d]", pagina - 1)); // read from stdin and specify page number with 1-based index
        op.addImage("jpg:-");               // write to stdout in jpg-format
        ByteArrayInputStream fis = new ByteArrayInputStream(imagen);
        ByteArrayOutputStream fos = new ByteArrayOutputStream();
        // Pipe pipe = new Pipe(fis,fos);
        Pipe pipeIn  = new Pipe(fis,null);
        Pipe pipeOut = new Pipe(null,fos);
        // set up command
        ConvertCmd convert = new ConvertCmd();
        convert.setInputProvider(pipeIn);
        convert.setOutputConsumer(pipeOut);
        convert.run(op);
        imgPagina = fos.toByteArray();
        }catch(Exception e){
            throw new Exception(
                    "Error al obtener la imágen de la página " + pagina, e);
        }
        return imgPagina;
    }

este método lo podemos utilizar en un servicio web/servlet para servir la imágen a través de una url

    @GET
    @Path("documento/{id}/imagen/pagina/{numero}")
    @Produces("image/jpeg")
    public Response getPaginaPromocion(@PathParam("id")Integer id, @PathParam("numero")Integer numero){
        Response response = null;
        try{
            Documento doc = Documento.get(id);
            response = Response.ok(doc.getPagina(numero), "image/jpeg").build();
        }catch(Exception e){
            String error = String.format("Error al obtener la página %d del documento %s", numero, id);
            log.error(error, e);
            response = Response.serverError().entity(String.format("{\"response\": {\"status\": -1, \"data\": \"%s\"}}", error)).build();
        }
        return response;
    }

Fuentes:

http://www.imagemagick.org/discourse-server/viewtopic.php?f=1&t=16615#p61020
http://stackoverflow.com/questions/4809314/imagemagick-is-converting-only-the-first-page-of-the-pdf
http://im4java.sourceforge.net/docs/dev-guide.html#piping
http://stackoverflow.com/questions/2091454/byte-to-inputstream-or-outputstream
http://im4java.sourceforge.net/api/

SmartGwt especifica 2 tipos de errores: de validación e irrecuperables.

Los errores de validación se representan en JSON de la siguiente manera

    {    "response":
           {   "status": -4,
           "errors":
               {   "field1": [
                       {"errorMessage": "First error on field1"},
                       {"errorMessage": "Second error on field1"}
                   ]
               }
           }
    }

de acuerdo a la documentación un error irrecuperable se representa de la siguiente forma

    {"response": {"status": -1, "data": "Error message..."}}

Pero cuando utilicé un RestDataSource en un SelectItem y ocurría un error en el servidor, la petición se reintentaba de forma cíclica. La solución fue agregar la propiedad totalRows a la respuesta.

    {"response": {"status": -1, "data": "Error message...", "totalRows": 0 }}

Fuentes:
http://www.smartclient.com/smartgwt/javadoc/com/smartgwt/client/docs/ErrorHandling.html
http://www.smartclient.com/smartgwt/javadoc/com/smartgwt/client/data/RestDataSource.html
http://forums.smartclient.com/showthread.php?t=22975

Si tienes una tabla(entidad) con una llave primaria compuesta por 2 o más columnas -y quieres crear un DataSource para enlazar un control a los datos- tendrías que hacerlo de la siguiente manera.
Supongamos que tenemos una tabla donde registramos una estadística mensual. Tendríamos la siguiente clase

public class MonthStat{
	long categoryId;
	int month;
	int year;
	double data;

	public MonthStat(){
	}
}

La llave primaria estaría conformada por el id de la categoría, el mes y el año del dato estadístico.
En SmartGwt vamos a crear el DataSource de la siguiente manera

DataSource monthStatsDS=new RestDataSource(){
	{
		setDataURL(Consts.REST_MONTHSTATS);
		setDataFormat(DSDataFormat.JSON);

		DataSourceField fldId=new DataSourceField("key", FieldType.TEXT);
		fldId.setPrimaryKey(true);
		fldId.setHidden(true);
		DataSourceField fldCategoryId=new DataSourceField("categoryId", FieldType.INTEGER);
		DataSourceField fldMonth=new DataSourceField("month", FieldType.INTEGER);
		DataSourceField fldYear=new DataSourceField("year", FieldType.INTEGER);
		DataSourceField fldData=new DataSourceField("data", FieldType.FLOAT);
		setFields(fldId,fldCategoryId,fldMonth,fldYear,fldData);
	}

	@Override
	protected void transformResponse(DSResponse response,
			DSRequest request, Object data) {
		Record[] monthStatRecord = response.getData();
		for(int i=0;i<monthStatRecord.length;i++){
			monthStatRecord[i].setAttribute("key",
					monthStatRecord[i].getAttribute("categoryId")+"#"+
					monthStatRecord[i].getAttribute("month")+"#"+
					monthStatRecord[i].getAttribute("year"));
		}
		super.transformResponse(response, request, data);
	}
};

Este DataSource obtiene los datos de un servicio REST. Lo interesante es que creamos un nuevo atributo ‘key’ en cada registro, donde concatenamos los atributos que forman la llave primaria -separados por el símbolo ‘#’- y asignamos ese campo como el primary key del DataSource.
Si utilizamos este DataSource en un SelectItem se complica un poco más la cosa, ya que este control sólo acepta un campo para el valor que va a mostrar y un campo para el valor real. En este caso tendríamos que descomponer la llave en sus elementos del lado del servidor.
Por ejemplo

SelectItem itmMonthStatData=new SelectItem("month","Select month");
itmMonthStatData.setOptionDataSource(monthStatsDS);
itmMonthStatData.setAutoFetchData(true);
itmMonthStatData.setDisplayField("month");
itmMonthStatData.setValueField("key");

nos enviaría al servidor un parámetro “month” -debido al nombre que utilizamos para el SelectItem- con un valor como “25#12#2012” y obtendríamos los elementos de la siguiente forma

@POST
public String create(
		@FormParam("month")String key){
	StringTokenizer token=new StringTokenizer(key,"#");
	Integer idCategoria=Integer.parseInt(token.nextToken());
	Integer month=Integer.parseInt(token.nextToken());
	Integer year=Integer.parseInt(token.nextToken());

	// haz lo que necesites con estos valores
}

Cabe mencionar que el uso de llaves primarias compuestas es un tema de debate. Se recomienda incluso no utilizarlas, sino mejor crear una nueva columna en nuestra tabla cuyo valor sea autogenerado por alguna secuencia o un UUID.

Fuentes:
http://www.smartclient.com/smartgwt/javadoc/com/smartgwt/client/data/DataSource.html#transformResponse(com.smartgwt.client.data.DSResponse, com.smartgwt.client.data.DSRequest, java.lang.Object)
http://www.smartclient.com/smartgwt/javadoc/com/smartgwt/client/data/DataSourceField.html#setPrimaryKey(java.lang.Boolean)

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

A la hora de migrar datos de un sistema a otro, no siempre se trata de copiar de una tabla a otra con la misma estructura. A veces, hay que copiar los valores de una columna de una tabla a otra. Para hacer esto en Oracle basta con utilizar una subconsulta de la siguiente manera

update usuarios u
set id_oficina=(
   select o.id
   from oficina_usuario o
   where u.id=o.id
)

Es importante que la subconsulta regrese un sólo valor para la condición que relaciona las tablas (‘where u.id=o.id_usuario’), de lo contrario fallará.

Ya sea que eres nostalgico, diseñador o desarrollador web seguramente haz tenido la necesidad de ejecutar una versión diferente a la que tienes instalada. En mi caso, la extensión GWT Developer Plugin -utilizada para depurar aplicaciones hechas con GWT- solo es compatible con las versiones 3.0 a la 6.0 (a la fecha) y tengo la 7.0 :S

Para instalar otras versiones hay que descargar -desde el servidor FTP de mozilla– y descomprimir en una carpeta las que necesitemos.

Una vez hecho esto tenemos que crear un nuevo perfil por cada versión que deseamos utilizar con el siguiente comando (cada perfil tendrá su propia carpeta en el directorio ~./mozilla/firefox)

firefox -no-remote -CreateProfile firefox-3.6.20

Puedes ver la configuración de los perfiles en el archivo ~./mozilla/firefox/profiles.ini
Listo, ya solo tienes que ejecutar la versión de firefox desde su carpeta

cd firefox-3.6.20
./firefox -no-remote -P firefox-3.6.20

No olvides desactivar las actualizaciones de firefox

También puedes crear un acceso directo en tu escritorio dando clic derecho y seleccionar “Create Launcher…”

Fuentes:

http://odyniec.net/blog/