No puedo ver archivos pdf ni xml en postgresql
Hay ocasiones cuando es necesario y útil, el guardar directamente en la base de datos archivos de distintos formatos. Por ejemplo, archivos pdf y xml.
Por motivos de las reformas fiscales en México, hemos estado trabajando arduamente en la adaptación del sistema contable para que poder cumplir con las obligaciones propias del SAT.
Uno de los requisitos fiscales a cumplir, es el que cada póliza contable debe contener adjuntas la facturas que justifiquen cada uno de los gastos registrados en la póliza. Claro está, estas facturas, archivos xml, deben estar debidamente timbrados por el SAT.
Así que, como parte de todas estas adecuaciones, se decidió grabar tanto el archivo pdf como el archivo xml en la base de datos. Y todo había venido funcionando de maravilla. Hasta que...
Bueno, hasta que nos dimos cuenta que al querer descargar los archivos, estos no traían la información correcta, solo mostraban caracteres y números.
Para esto, debo comentar que se reciben todas las facturas de los proveedores por un portal externo, el cual guarda los archivos xml y pdf en Postgresql. Y ese portal está funcionando muy bien. Muestra los archivos de manera correcta.
El problema surgió a la hora de leer estos registros de las facturas, y guardarlos en Oracle juntos con las pólizas contables.
Como sabrán en Oracle, los datos binarios se guardan en tipo 'Blob'. Por lo menos así lo genera Hibernate. Por su parte, en Postgresql se guardan en 'bytea'.
La tarea parecía muy sencilla. Leer el registro de Postgresql, copiar los datos al POJO correspondiente en Oracle, y guardar. Pero cual va siendo la sorpresa, que al querer ver los datos guardados en Oracle solo se ven caracteres que no dicen nada!
Y mayor fue la sorpresa, al ver que estos caracteres se mostraban desde el mismo instante que se leía el registro de Postgresql! Es decir, en el portal del proveedor sí se veían los archivos de manera correcta al descargarlos, y cuando se leían estos mismos registros desde el sistema contable, solo salía basura!
Después de dos días de hacer prueba tras prueba, con distintos códigos encontrados en Google y hacer toda locura posible, se encontró la solución!
Y es de lo más simple! Se decidió modificar el proceso inicial en el sistema contable. En lugar de descargar los archivos desde Oracle, se iban a descargar ahora desde Postgresql. Al intentarlo, volvió a salir basura.
Esto llamó poderosamente la atención hacia los jdbc. Al hacer pruebas en Oracle, había posiblidades de que la interpretación de un byte[] a un Blob ocasionara los desmanes en los datos. O que el incluso el Hibernate tuviera algún bug.
Pero cuando se intentaron leer los datos directo de Postgresql, donde el portal del proveedor sí podía leerlos bien, y salió basura, entonces sospechamos del jdbc.
Así que, se actualizó el jdbc de Postgresql al JDBC41 Postgresql Driver, Version 9.3-1102, ya que este sistema está utilizando java 1.7, y se hizo la prueba nuevamente de descargar uno de los archivos. Y voalá! Como por arte de magia apareció el pdf y el xml de manera correcta!
Falta hacer algunas pruebas ahora con la idea original, de pasar a Oracle estos archivos. Ya les estaremos informando!
Actualización:
Bueno, continuando con el tema, aquí les presentamos los últimos avances.
Una vez que todo funcionó bien leyendo los archivos desde Postgresql, el siguiente paso fue probar el guardar y leers estos registros en Oracle.
Para explicarlo claramente, aquí les dejamos el código.
Esta es el POJO que está mapeando la clase desde Postgresql:
Esta es la clase que está mapeando hacia Oracle:
En nuestro caso, desarrollamos el sistema con Spring y Hibernate, utilizando el modelo MVC.
Aquí les mostramos la clase DAO donde se puede apreciar la forma como se llenan los atributos Blob:
Finalmente, esta es la manera como leemos los datos 'Blob' para poder descargar los archivos:
Conclusión
Este fue un caso muy interesante, porque jamás nos imaginamos que los archivos no se pudieran descargar por motivos ajenos a la programación, es decir, a las instrucciones que nosotros estábamos utilizando para manipular los registros.
La enseñanza que esta experiencia nos ha dejado, es que es necesario tener actualizados todos los componentes del sistema, cada librería tiene su por qué y su valor único para el correcto funcionamiento del software donde se encuentran funcionando y haciendo sinergia con otros componentes.
Por motivos de las reformas fiscales en México, hemos estado trabajando arduamente en la adaptación del sistema contable para que poder cumplir con las obligaciones propias del SAT.
Uno de los requisitos fiscales a cumplir, es el que cada póliza contable debe contener adjuntas la facturas que justifiquen cada uno de los gastos registrados en la póliza. Claro está, estas facturas, archivos xml, deben estar debidamente timbrados por el SAT.
Así que, como parte de todas estas adecuaciones, se decidió grabar tanto el archivo pdf como el archivo xml en la base de datos. Y todo había venido funcionando de maravilla. Hasta que...
Bueno, hasta que nos dimos cuenta que al querer descargar los archivos, estos no traían la información correcta, solo mostraban caracteres y números.
Para esto, debo comentar que se reciben todas las facturas de los proveedores por un portal externo, el cual guarda los archivos xml y pdf en Postgresql. Y ese portal está funcionando muy bien. Muestra los archivos de manera correcta.
El problema surgió a la hora de leer estos registros de las facturas, y guardarlos en Oracle juntos con las pólizas contables.
Como sabrán en Oracle, los datos binarios se guardan en tipo 'Blob'. Por lo menos así lo genera Hibernate. Por su parte, en Postgresql se guardan en 'bytea'.
La tarea parecía muy sencilla. Leer el registro de Postgresql, copiar los datos al POJO correspondiente en Oracle, y guardar. Pero cual va siendo la sorpresa, que al querer ver los datos guardados en Oracle solo se ven caracteres que no dicen nada!
Y mayor fue la sorpresa, al ver que estos caracteres se mostraban desde el mismo instante que se leía el registro de Postgresql! Es decir, en el portal del proveedor sí se veían los archivos de manera correcta al descargarlos, y cuando se leían estos mismos registros desde el sistema contable, solo salía basura!
Después de dos días de hacer prueba tras prueba, con distintos códigos encontrados en Google y hacer toda locura posible, se encontró la solución!
Y es de lo más simple! Se decidió modificar el proceso inicial en el sistema contable. En lugar de descargar los archivos desde Oracle, se iban a descargar ahora desde Postgresql. Al intentarlo, volvió a salir basura.
Esto llamó poderosamente la atención hacia los jdbc. Al hacer pruebas en Oracle, había posiblidades de que la interpretación de un byte[] a un Blob ocasionara los desmanes en los datos. O que el incluso el Hibernate tuviera algún bug.
Pero cuando se intentaron leer los datos directo de Postgresql, donde el portal del proveedor sí podía leerlos bien, y salió basura, entonces sospechamos del jdbc.
Así que, se actualizó el jdbc de Postgresql al JDBC41 Postgresql Driver, Version 9.3-1102, ya que este sistema está utilizando java 1.7, y se hizo la prueba nuevamente de descargar uno de los archivos. Y voalá! Como por arte de magia apareció el pdf y el xml de manera correcta!
Falta hacer algunas pruebas ahora con la idea original, de pasar a Oracle estos archivos. Ya les estaremos informando!
Actualización:
Bueno, continuando con el tema, aquí les presentamos los últimos avances.
Una vez que todo funcionó bien leyendo los archivos desde Postgresql, el siguiente paso fue probar el guardar y leers estos registros en Oracle.
Para explicarlo claramente, aquí les dejamos el código.
Esta es el POJO que está mapeando la clase desde Postgresql:
public class InformeProveedorDetalle extends BaseObject { private Long id; private Long version; private String folioFactura; private String folioFiscal; private byte[] pdfFile; private byte[] xmlFile; private String rfc; }Como pueden ver, los atributos donde se guardarán los archivos son tipo 'byte[]'.
Esta es la clase que está mapeando hacia Oracle:
public class MovimientoFacturaSAT extends BaseObject { private Long id; private Integer version; private Poliza poliza; private String numMovto; //Numero de movimiento private String contrarecibo; private byte[] xmlFile; private byte[] pdfFile; private Blob xmlFileBlob; private Blob pdfFileBlob; private String folioFactura; private String folioFiscal; private String rfc; private User usuario; private Date fecha; }Se puede apreciar que hay dos atributos para tipo de archivo. Un atributo tipo 'Blob' y otra tipo 'byte[]'.
En nuestro caso, desarrollamos el sistema con Spring y Hibernate, utilizando el modelo MVC.
Aquí les mostramos la clase DAO donde se puede apreciar la forma como se llenan los atributos Blob:
public void saveMovimientoFacturaSAT(final MovimientoFacturaSAT movimientoFacturaSAT) { Blob blob = Hibernate.getLobCreator(getSession()).createBlob(movimientoFacturaSAT.getXmlFile()); movimientoFacturaSAT.setXmlFileBlob(blob); blob = Hibernate.getLobCreator(getSession()).createBlob(movimientoFacturaSAT.getPdfFile()); movimientoFacturaSAT.setPdfFileBlob(blob); getHibernateTemplate().saveOrUpdate(movimientoFacturaSAT); }Esta es la clase Service, donde se leen los archivos de Postgresql y se asignan a la calse que mapea hacia Oracle:
movSAT = new MovimientoFacturaSAT(); movSAT.setContrarecibo(cont.getId().toString()); movSAT.setFecha(new Date()); movSAT.setFolioFactura(det.getFolioFactura()); movSAT.setFolioFiscal(det.getFolioFiscal()); movSAT.setRfc(det.getRfc()); movSAT.setNumMovto(mov.getKey().getMovto().toString()); movSAT.setPoliza(poliza); movSAT.setUsuario(usMgr.getUserByUsername((String)params.get("username"))); in = new ByteArrayInputStream(det.getXmlFile()); out = new ByteArrayOutputStream(det.getXmlFile().length); try { FileCopyUtils.copy(in, out); movSAT.setXmlFile(out.toByteArray()); } catch (IOException ex) { ; } finally { try { in.close(); out.close(); } catch (IOException ex) { ; } } in = new ByteArrayInputStream(det.getPdfFile()); out = new ByteArrayOutputStream(det.getPdfFile().length); try { FileCopyUtils.copy(in, out); movSAT.setPdfFile(out.toByteArray()); } catch (IOException ex) { ; } finally { try { in.close(); out.close(); } catch (IOException ex) { ; } } movSATDao.saveMovimientoFacturaSAT(movSAT);Llamo la atención hacia la forma de copiar los 'ByteArrays' de una clase a otra.
Finalmente, esta es la manera como leemos los datos 'Blob' para poder descargar los archivos:
OutputStream out = response.getOutputStream(); response.setContentType("application/pdf"); response.setHeader("Content-Disposition", "attachment; filename=\"factura.pdf\""); try { mov = dao.getMovimientoFacturaSAT(new Long(request.getParameter("movSATId"))); FileCopyUtils.copy(mov.getPdfFileBlob().getBinaryStream(), out); } catch (Exception ex) { log.error("Error generico al intentar obtener el movimientoFacturaSAT con id {}", request.getParameter("movSATId")); ex.printStackTrace(); }
Conclusión
Este fue un caso muy interesante, porque jamás nos imaginamos que los archivos no se pudieran descargar por motivos ajenos a la programación, es decir, a las instrucciones que nosotros estábamos utilizando para manipular los registros.
La enseñanza que esta experiencia nos ha dejado, es que es necesario tener actualizados todos los componentes del sistema, cada librería tiene su por qué y su valor único para el correcto funcionamiento del software donde se encuentran funcionando y haciendo sinergia con otros componentes.
Comentarios
Publicar un comentario