viernes, 5 de octubre de 2007

Forms 6 y Forms 10g: Generar archivo excel (XLS)

En Jakarta hay un proyecto que consiste en un API para manipular y generar documentos de Office sin necesidad de tener Office instalado, luego los documentos resultantes se pueden abrir con cualquier suite ofimática, como por ejemplo OpenOffice.

http://poi.apache.org/trans/es/index.html

En el momento de escribir esto la última versión era la 3.0.1 y las clases necesarias se encuentran en el archivo poi-3.0.1-FINAL-20070705.jar

Para poder usar estas clases en un programa de forms tenemos que hacer los siguientes pasos:

Forms 10g:

  • En esta ventana seleccionamos las clases:
    • org.apache.poi.hssf.usermodel.HSSFWorkbook
    • org.apache.poi.hssf.usermodel.HSSFRow
    • org.apache.poi.hssf.usermodel.HSSFSheet
    • org.apache.poi.hssf.usermodel.HSSFCell
    • java.io.FileOutputStream (posiblemente tengamos que añadir al CLASSPATH el archivo rt.jar
  • Una vez importadas las clases nos crea paquetes PL/SQL para poder interactuar con ellas, por lo que ahora simplemente hay que escribir el código PL/SQL normal.
  • Para poder ejecutar el programa hay que añadir el archivo poi-3.0.1-FINAL-20070705.jar al CLASSPATH en el servidor. Para ello miramos en el archivo formsweb.cfg que se encuentra en $ORACLE_HOME/forms/server la variable envFile, y al archivo que apunta es donde tenemos que modificar la variable CLASSPATH.
Forms 6i:

  • Hay que usar una máquina virtual de Java versión 1.4.2 o superior, lo he probado con la 1.4.2_06 y con 1.6.0_02.
  • Añadir a la variable de entorno PATH las carpetas: (Sustituir c:\program files\java\jdk1.6.0_02 por la carpeta en que tengamos instalado el jdk, si no lo configuramos correctamente nos dará el error: "PDE-UJI001 Fallo al crear JVM." al intentar importar las clases)
    • C:\Program Files\Java\jdk1.6.0_02\bin
    • C:\Program Files\Java\jdk1.6.0_02\jre\bin
    • C:\Program Files\Java\jdk1.6.0_02\jre\bin\client
  • Al igual que en Forms 10g hay que añadir a la variable CLASSPATH el archivo poi-3.0.1-FINAL-20070705.jar
  • Añadir también al CLASSPATH el archivo importer.jar que se encuentra en $ORACLE_HOME\tools\common60\java
  • Al igual que en Forms 10g, en el programa que se quiera usar hay que importar las mismas clases Java que se indican en el apartado para Forms 10g (esas son necesarias para los ejemplos, pero seguramente que en un caso real tengamos que importar más), para ello vamos al menú "Programa" y luego a "Importar Clases Java...".


Ejemplos:

Ejemplo New Workbook de Jakarta POI

HSSFWorkbook wb = new HSSFWorkbook();
FileOutputStream fileOut = new FileOutputStream("workbook.xls");
wb.write(fileOut);
fileOut.close();

Equivalente en Forms

DECLARE
v_wb      ORA_JAVA.JOBJECT;
v_fileout ORA_JAVA.JOBJECT;
BEGIN
v_wb := hssfworkbook.new();
v_fileout := fileoutputstream.new('workbook.xls');
hssfworkbook.write(v_wb, v_fileout);
fileoutputstream.close(v_fileout);
END;

Ejemplo New Shet de Jakarta POI


HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet1 = wb.createSheet("new sheet");
HSSFSheet sheet2 = wb.createSheet("second sheet");
FileOutputStream fileOut = new FileOutputStream("workbook.xls");
wb.write(fileOut);
fileOut.close();

Equivalente en Forms:

DECLARE
v_wb       ORA_JAVA.JOBJECT;
v_fileout  ORA_JAVA.JOBJECT;
v_sheet1   ORA_JAVA.JOBJECT;
v_sheet2   ORA_JAVA.JOBJECT;
BEGIN
v_wb := hssfworkbook.new();
v_sheet1 := hssfworkbook.createsheet(v_wb, 'new sheet');
v_sheet2 := hssfworkbook.createsheet(v_wb, 'second sheet');
v_fileout := fileoutputstream.new('workbook.xls');
hssfworkbook.write(v_wb, v_fileout);
fileoutputstream.close(v_fileout);
END;

Ejemplo Creating Cells de Jakarta POI


HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet("new sheet");

// Create a row and put some cells in it. Rows are 0 based.
HSSFRow row = sheet.createRow((short)0);
// Create a cell and put a value in it.
HSSFCell cell = row.createCell((short)0);
cell.setCellValue(1);

// Or do it on one line.
row.createCell((short)1).setCellValue(1.2);
row.createCell((short)2).setCellValue("This is a string");
row.createCell((short)3).setCellValue(true);

// Write the output to a file
FileOutputStream fileOut = new FileOutputStream("workbook.xls");
wb.write(fileOut);
fileOut.close();

Equivalente en Forms:

DECLARE
v_wb         ORA_JAVA.JOBJECT;
v_fileout    ORA_JAVA.JOBJECT;
v_sheet      ORA_JAVA.JOBJECT;
v_row        ORA_JAVA.JOBJECT;
v_cell       ORA_JAVA.JOBJECT;
BEGIN
v_wb := hssfworkbook.new();
v_sheet := hssfworkbook.createsheet(v_wb, 'new sheet');
v_row := hssfsheet.createrow(v_sheet, 0);
v_cell := hssfrow.createcell(v_row, 0);
hssfcell.setcellvalue(v_cell, 1);
v_cell := hssfrow.createcell(v_row, 1);
hssfcell.setcellvalue(v_cell, 1.2);
v_cell := hssfrow.createcell(v_row, 2);
hssfcell.setcellvalue(v_cell, 'This is a string');
v_cell := hssfrow.createcell(v_row, 3);
hssfcell.setcellvalue(v_cell, TRUE);
v_fileout := fileoutputstream.new('workbook.xls');
hssfworkbook.write(v_wb, v_fileout);
fileoutputstream.close(v_fileout);
END;

Ejemplo para enviar el contenido de un bloque a una excel:

DECLARE
v_wb               ORA_JAVA.JOBJECT;
v_fileout          ORA_JAVA.JOBJECT;
v_sheet            ORA_JAVA.JOBJECT;
v_row              ORA_JAVA.JOBJECT;
v_cell             ORA_JAVA.JOBJECT;
v_fin              BOOLEAN := FALSE;
v_bloque           VARCHAR2(30) := :system.cursor_block;
v_record_anterior  NUMBER := :system.cursor_record;
v_item_anterior    VARCHAR2(61) := :system.cursor_item;
v_item             VARCHAR2(30);
v_num_celda        NUMBER;
v_num_fila         NUMBER;
BEGIN
v_wb := hssfworkbook.new();
v_sheet := hssfworkbook.createsheet(v_wb, 'new sheet');
v_num_fila := 0;

FIRST_RECORD;

WHILE NOT v_fin LOOP
v_row := hssfsheet.createrow(v_sheet, v_num_fila);
v_num_fila := v_num_fila + 1;
v_item := Get_Block_Property(v_bloque, FIRST_ITEM);
v_num_celda := 0;

WHILE v_item IS NOT NULL LOOP
v_cell := hssfrow.createcell(v_row, v_num_celda);
hssfcell.setcellvalue(v_cell, NAME_IN(v_bloque || '.' || v_item));
v_item := Get_Item_Property(v_bloque || '.' || v_item, NEXTITEM);
v_num_celda := v_num_celda + 1;
END LOOP;

IF :system.last_record = 'TRUE' THEN
v_fin := TRUE;
ELSE
NEXT_RECORD;
END IF;
END LOOP;

v_fileout := fileoutputstream.new('workbook.xls');
hssfworkbook.write(v_wb, v_fileout);
fileoutputstream.close(v_fileout);

GO_RECORD(v_record_anterior);
GO_ITEM(v_item_anterior);
END;

NOTA 15/12/2009: Las versiones recientes de las librerías de Jakarta POI están compiladas para usar una máquina virtual de java superior a la que tiene Forms 10g. Al importar en Forms10g sale este mensaje: "Se ha producido una excepción: java.lang.UnsupportedClassVersionError: org/apache/poi/hssf/usermodel/HSSFWorkbook (Unsupported major.minor version 49.0)". Con la versión 3.0.1 de las librerías funciona perfectamente. Esta versión se puede descargar de aqui: http://sites.google.com/site/elfeme/files/poi-3.0.2-FINAL-20080204.zip?attredirects=0&d=1