Barcode4J en JRuby y Rails

Agosto 13th, 2010

En el post anterior había explicado el uso de Gbarcode, una librería para generación de códigos de barras con Ruby. El problema es que esta librería no se puede utilizar en Jruby ya que tiene extensiones nativas en C, cosa que Jruby aún no soporta.
Después de investigar alternativas de generación de codigos de barras para java como Zxing y Barbecue. Me quedé con Barcode4j por facilidad de implementación, documentación (la cual es muy completa) y sobre todo estabilidad.
A continuación paso a comentarles como utilizar esta librería en JRuby.

1) Lo primero es descargarse en paquete binario del sitio o bien de este enlace directo.
2) Al descomprimir el Zip, copiamos el contenido del directorio Build al directorio /lib de nuestra instalación de JRuby

3) Ahora vamos al código:


require 'java'

#Importamos algunas librerías que vamos a utilizar
import 'java.awt.image.BufferedImage'
import 'java.io.OutputStream'
import 'java.io.FileOutputStream'

#Importamos las librerías de los códigos de barras (Barcode4j) que necesitamos
import 'org.krysalis.barcode4j.impl.code39.Code39Bean'
import 'org.krysalis.barcode4j.impl.code128.Code128Bean'
import 'org.krysalis.barcode4j.impl.int2of5.Interleaved2Of5Bean'
import 'org.krysalis.barcode4j.impl.codabar.CodabarBean'
import 'org.krysalis.barcode4j.impl.code128.EAN128Bean'
import 'org.krysalis.barcode4j.impl.pdf417.PDF417Bean'
import 'org.krysalis.barcode4j.impl.upcean.EAN13Bean'
import 'org.krysalis.barcode4j.impl.upcean.EAN8Bean'
import 'org.krysalis.barcode4j.impl.upcean.UPCABean'
import 'org.krysalis.barcode4j.impl.datamatrix.DataMatrixBean'
import 'org.krysalis.barcode4j.output.bitmap.BitmapCanvasProvider'
import 'org.krysalis.barcode4j.tools.UnitConv'

#Creamos el Bean y establecemos los dpi y wide_factor
bean = Interleaved2Of5Bean.new()
dpi = 150
bean.wide_factor = 3

#Creamos la imagen
ofile = java.io.File.new('/home/laptop/barcodes/barcode.png')
out = FileOutputStream.new(ofile)
canvas = BitmapCanvasProvider.new(out,"image/x-png", dpi, BufferedImage::TYPE_BYTE_BINARY, false, 0)

#Generamos el código de barras
#El segundo parámetro que pasamos es el número del que deseamos generar el codigo de barras
bean.generate_barcode(canvas, '1234567890');
canvas.finish
out.close

Con esto, generamos una imagen con nuestro codigo de barras en /home/laptop/barcodes/barcode.png la cual se puede incluir en cualquier pdf/html/odf, etc.

Espero les sea útil. Cualquier duda, no duden en comentar.

Hay veces que el usuario necesita subir archivos, pero de una manera “masiva”, no guardando de a uno. Un claro ejemplo de esto es GoogleDocs,
que te deja subir varios documentos a la vez, antes de empezar a verlos.
Utilizando un plugin de jquery, en rails esto se hace de una manera muy transparente.
El plugin en cuestión se llama MultiFileUpload, en su página encontraremos una buena documentación de como usarlo correctamente
Lo que nos interesa es como implementarlo en rails y que todos estos archivos que seleccionamos se almacenen en nuestra base de datos.

Para comenzar tenemos que incluir las librerias del plugin en el aplication.html.erb

 <% javascript_include_tag :default, 'multiple-file-upload/jquery.MultiFile.js', 'multiple-file-upload/jquery.MetaData.js' %>

En nuestra vista creamos el formulario, para subir los archivos

<% form_for(:archivo_digital, :html => {:multipart => true },:url => create_archivo_digital_path) do |f| %>
      <ul id="form">
	    <%= file_field_tag :files, :class => 'multi file', :name => 'pdf_files[]'%>
          <li>
            <%= f.submit 'Subir' %>
            <%= f.submit 'Cancelar' %>
          </li>
      </ul>
<% end %>

Expliquemos un poco el código:

En necesario establecer :multipart => true, para que el formulario admita la carga de archivos.
file_field_tag nos crea el tag para poder abrir el cuadro de diálogo de carga de archivos de un navegador:
:class => ‘multi file’, esta clase es la que utiliza MultiFileUpload para hacer la magia de subir varios archivos
:name => ‘pdf_files[]‘ esto es muy necesario, porque el plugin crea un arreglo con todos los archivos, pero para que ruby sepa
que nos referimos a un arreglo tenemos que poner [].
Por último tenemos dos botones, el de Subir, que va a subir todos los archivos de una sola vez y el de Cancelar, que hará lo propio.

En nuestro controller vamos a tener

#Renderiza el formulario para subir los archivos
  def new
    @archivo_digital = ArchivoDigital.new
    respond_to do |format|
      format.html
    end
  end
 
  def create
    respond_to do |format|
      if params[:commit] == "Subir"
        unless params[:pdf_files].blank?
          params[:pdf_files].each do |archivo|
            params[:archivo_digital][:nombre_archivo] = archivo
            params[:archivo_digital][:archivo] = archivo.read
            @archivo_digital = ArchivoDigital.new(params[:archivo_digital])
            if @archivo_digital.save
              flash[:notice] = 'Archivo agregado'
            end
          end
          format.html{redirect_to archivos_digitales_path}
        else
          flash[:error] = 'Debe seleccionar al menos un archivo'
        end
      else
           format.html{redirect_to archivos_digitales_path}
      end
    end
  end

Expliquemos un poco el código:
Sobre el primer método no hay mucho que decir, solo nos renderiza el formulario que creamos en el paso anterior
El método create es el que hace todo, para empezar tenemos una condición donde pregunta si params[:commit] == “Subir”
esto es para que diferencie entre el botón subir y el cancelar. Cuando presionamos un botón, rails inmediatamente manda un parámetro, llamado
commit con el nombre del botón. Con está condición lo que hacemos es darle tareas diferentes a cada botón.
Si no se cumple la condición, es porque se presionó el botón “Cancelar” y nos redirigirá al listado de archivos.
En caso de que la condición se cumpla, tenemos otro condicional: unless params[:pdf_files].blank?, esto es para saber si se seleccionó algun archivo_digital
y caso contrario muestra un flash[:error]. Si se cumple la condición, recorremos el arreglo y vamos guardando en nuestra base de datos el nombre del
archivo y el archivo en sí.

Bueno, esto es una manera sencilla de subir archivos de forma “masiva” con Jquery y Rails, cualquier cosa no duden en preguntar

Uno de los grandes problemas en el desarrollo con Ruby on Rails son los reportes multipágina. Debido a que el HTML (inclusive HTML 5) no soporta multipágina, si utilizamos Jruby tenemos la posibilidad de usar cualquier librería Java en nuestro desarrollo.
Afortunadamente en Java tenemos JasperReports (http://jasperforge.org/), una excelente solución al problema antes mencionado.

Para poder incluir un reporte realizado con JasperReports en nuestra aplicación Jruby necesitamos:

1) Descargar I-Report, la herramienta de administracion de reportes de JasperReports. http://jasperforge.org/projects/ireport y descomprimirlo.

2) Dentro del directorio del i-report, ir a modules/ext/ y copiar todos los archivos .jar (si, todos :D ) al directorio lib de la instalación de JRuby. De esta manera, ya incluimos las librerías necesarias y tenemos preparado nuestro JRuby para utilizar JasperReports.

3) Nos resta crear un reporte para prueba, si nunca hiciste un reporte con i-report: http://jasperforge.org//website/ireportwebsite/IR%20Website/ir_design_a_report.html?header=project&target=ireport

4) Finalmente el código para correr nuestro reporte es el siguiente:

require 'java'
import 'oracle.jdbc.OracleDriver' #Aqui necesitas Utilizar el Driver de la Base de datos que estas usando, en mi caso es oracle
import 'net.sf.jasperreports.engine.JasperCompileManager'
import 'org.apache.commons.dbcp.BasicDataSource'
import'java.util.HashMap'
import'net.sf.jasperreports.engine.JasperFillManager'
import'net.sf.jasperreports.engine.JasperExportManager'                                                                             

#Creo el datasource
basicdatasource = BasicDataSource.new
basicdatasource.driver_class_name = 'oracle.jdbc.OracleDriver'
basicdatasource.username = 'usuario'
basicdatasource.password = 'password'
basicdatasource.url = 'jdbc:oracle:thin:@localhost:1521:XE'
basicdatasource.connection
conexion = basicdatasource.connection

#Compilamos el reporte
jasperReport = JasperCompileManager.compile_report('/url_de_tu_archivo_jrxml/reporte.jrxml')
#Para pasar los parámetros, definimos un objeto HashMap
m = HashMap.new
m.put('parametro_1','valor_parametro_1')
m.put('parametro_2','valor_parametro_2')
m.put('parametro_n','valor_parametro_n')

#Genero el reporte
jasperPrint = JasperFillManager.fill_report(jasperReport, m,conexion)                           

#Exporto el PDF
JasperExportManager.export_report_to_pdf_file(jasperprint, 'path_al_archivo_PDF.pdf')

Si deseamos generar reportes en Rails, podemos por ejemplo ubicar los reportes en el directorio public/reportes y utilizar send_file para enviarlos, por ejemplo:

JasperExportManager.export_report_to_pdf_file(jasperprint, RAILS_ROOT+"/public/reportes/reporte.pdf")
send_file RAILS_ROOT+"/public/reportes/reporte.pdf"

Espero les sea de utilidad, cualquier cosa comenten y trataré de despejar dudas :)

Gbarcode es una librería de generación de códigos de barra para Ruby. Es una extensión de C que envuelve el proyecto  GNU Barcode. Se distribuye en formato GEM

Link: http://gbarcode.rubyforge.org/

Ejemplo de uso:

require 'rubygems'
require 'gbarcode'

# Incluir el módulo

include Gbarcode

# Existen tres pasos para generar un codigo de barras
# 1) preparar el espacio para el string
# 2) codificar el string como un codigo de barras
# 3) imprimir el codigo de barras

# preparar el codigo de barras para el string "TEST1234"

bc = barcode_create("TEST1234")

# codificar el codigo de barras usando code 39,
# desde que code 39 no usa dígito de verificacion (checksum),
# lo podemos pasar en un flag

barcode_encode(bc, BARCODE_NO_CHECKSUM | BARCODE_39)

#imprimir el codigo de barras usando postcript

barcode_print(bc, File.new("testout.ps", "w"), BARCODE_OUT_PS)

# ó

barcode_print(bc, File.new("testout.eps", "w"), BARCODE_OUT_EPS)

Si bien hace bastante tiempo que soy usuario de GNU/Linux, no suelo crear tareas en cron con frecuencia por lo que necesito investigar su poderosa sintáxis cada vez que debo crear trabajos que deben ejecutarse a intervalos regulares.

Hace poco por casualidad me topé con Whenever, una gema de Ruby que nos permite crear tareas en cron de manera muy sencilla. A través de un DSL nos abstrae de la complejidad de la sintáxis de cron. Whenever está muy integrado al framework de desarrollo web Ruby on Rails, aunque puede utilizarse en un programa independiente que genera salidas de tareas para cron y hasta actualiza el archivo crontab.  En este post vamos a ver la manera de crear tareas con Whenever desde el punto de vista de un Administrador de Sistemas.

Read the rest of this entry »

En el proceso de autenticación, una aplicación permitirá a usuarios autenticados una serie de servicios permitidos. Cuando este usuario intenta acceder a un recurso en la aplicacion, tiene que tomar la decisión sobre qué recursos son accesibles con los permisos que tiene asignados o con otras características.

La decisión si a determinado usuario se le permite acceder a un recurso dentro de la aplicación se llama “decisión de control de acceso”. Se basa en el estado de la autenticación del usuario, y de la naturaleza de los recursos y los atributos de acceso. En Spring security, las decisiones de control de acceso son llevados a cabo por los managers de decisión de acceso, los cuales deben implementar la interfaz AccessDecisionManager. Cada uno es libre de crear su propio manager de decisión de acceso implementando esta interfaz, de todas maneras Spring Security viene con tres managers que implementan esta interfaz basado en el método de votos.

Read the rest of this entry »

REST con Rails

Diciembre 29th, 2009

El uso de REST con Ruby on Rails es extremadamente relajante, una vez que comienzas a utilizar REST y te acostumbras a trabajar de esa forma, no quieres volver a la forma tradicional. Esta es una guía de conceptos básicos de REST y su aplicación en Rails.

REST son las siglas de Representational State Transfer (Transferencia de Estado Representacional), es una técnica de arquitectura software para sistemas hipermedia distribuidos como la World Wide Web. El término se originó en el año 2000, en una tesis doctoral sobre la web escrita por Roy Fielding, uno de los principales autores de la especificación del protocolo HTTP y ha pasado a ser ampliamente utilizado por la comunidad de desarrollo.

Read the rest of this entry »

Los lenguajes de script se vuelven cada día más populares en gran parte a su sencillez, expresividad y potencia, entre los más populares tenemos a Python, Perl, Groovy y Ruby. Cada uno tiene sus ventajas y desventajas y debemos tener en cuenta estas características para elegir la herramienta adecuada para el trabajo.

Esta pequeña guía (en inglés) presenta las características más importantes de cada uno, trayendo un poco de luz sobre el tema.

buggy-sm
FindBugs es una aplicación desarrollada por la Universidad de Maryland cuyo objetivo es buscar bugs en programas Java. Está basado en el concepto de patrones de bug. Un patrón de bug es un idioma de código que a menudo es un error. Los patrones de bugs aparecen por una variedad de razones:

  • Dificultad de algunas características del lenguaje.
  • Falta de comprensión de los métodos de la API.
  • Errores de variación cuando el código es modificado durante el mantenimiento.
  • Una variedad de errores: errores de tipeo, uso incorrecto de los operadores booleanos, etc.

FindBugs usa análisis estático para inspeccionar el bytecode de Java en busca de patrones de bugs. Con análisis estático nos referimos a que puede encontrar errores simplemente inspeccionando el código de un programa: ejecutarlo no es necesario. Esto hace a FindBugs muy fácil de usar. En la práctica, la tasa de falsas advertencias reportadas por FindBugs es menor al 50%.

Instalación y ejecución

La manera más fácil de instalar FindBugs es bajar la distribución binaria que viene empaquetada en forma de archivo tar.gz o zip. FindBugs requiere JRE (or JDK) 1.5.0 o posterior para poder ejecutarse. Sin embargo puede analizar programas compilados en cualquier versión de Java. Un vez que lo bajamos lo descomprimimos de la siguiente manera:

tar -xvf findbugs-1.3.9.tar.gz
cd findbugs-1.3.9/
java -jar lib/findbugs.jar

FindBugs clasifica los bugs en las siguientes categorías

  • Correcto pero probable bug: un error de codificación aparente resultando en código que probablemente no era lo que el programador tenía en mente.
  • Mala Prácticas: violaciones a las prácticas de codificación esenciales y recomendadas, por ejemplo: uso incorrecto del finalize.
  • Código Dudoso: esto es código confuso, anómalo, o escrito de una manera que lleva a si mismo a errores, por ejemplo: casts sin confirmar, chequeos de nulos redundantes, etc.

Muchas veces necesitamos calcular y mostrar en una forma legible el tiempo transcurrido desde una fecha hasta el día de hoy. Por ejemplo en twitter podemos ver el tiempo transcurrido de un tweet hasta el momento.
twitter_time_ago

En Rails este proceso es muy sencillo utilizando el helper time_ago_in_words(), enviando como parámetro la fecha en la que ocurrió el evento. Es importante que el parámetro que le enviamos sea una fecha, en caso contrario nos dará una excepción de error de tipo de datos.
Por ejemplo si queremos saber cuanto tiempo pasó desde que se creó un ticket en nuestra base de datos, en la vista colocamos :

Esto nos dará un resultado como el ejemplo de la imagen, supongamos que pasaron 7 días:

# => 7 days

Hasta alli todo perfecto, pero que pasa si queremos nuestro resultado en castellano?, tenemos que redefinir en nuestro application_helper el método distance_of_time_in_words, simplemente copiamos y pegamos el siguiente código en nuestro application_helper.rb (o en cualquier helper, si solo lo queremos usar en un lugar específico)

def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false)
     from_time = from_time.to_time if from_time.respond_to?(:to_time)
     to_time = to_time.to_time if to_time.respond_to?(:to_time)
     distance_in_minutes = (((to_time - from_time).abs)/60).round
     distance_in_seconds = ((to_time - from_time).abs).round

     case distance_in_minutes
       when 0..1
         return (distance_in_minutes == 0) ? 'menos de um minuto' : '1 minuto' unless include_seconds
         case distance_in_seconds
           when 0..4   then 'menos de 5 segundos'
           when 5..9   then 'menos de 10 segundos'
           when 10..19 then 'menos de 20 segundos'
           when 20..59 then 'menos de um minuto'
         else             '1 minuto'
         end

        when 2..44           then "#{distance_in_minutes} minutos"
        when 45..89          then 'aproximadamente 1 hora'
        when 90..1439        then "aproximadamente #{(distance_in_minutes.to_f / 60.0).round} horas"
        when 1440..2879      then '1 dia'
        when 2880..43199     then "#{(distance_in_minutes / 1440).round} dias"
        when 43200..86399    then 'aproximadamente 1 mes'
        when 86400..525959   then "#{(distance_in_minutes / 43200).round} meses"
        when 525960..1051919 then 'aproximadamente 1 año'
     else                      "mas de #{(distance_in_minutes / 525960).round} años"

   end
end

Luego probamos nustra aplicación nuevamente y veremos que el resultado cambio a:

# => 7 dias