Un principiante en las Artes Gráficas Una experiencia en un sector que nos envuelve… El blog personal de David Pinelo.

10Dic/09Desactivado

AbanQ: Integrando con JasperServer / JasperReports (II)

Bien, la idea es usar una librería C++ para interaccionar con webservices. Para ello, escogí el toolkit gSOAP. Librería en software libre que permite crear aplicaciones tanto clientes (consumidores) como servidores de webservices.

Nosotros vamos a hacer un uso muy parcial de la misma, ya que no vamos a instalar ningún servidor ni nada por el estilo, y sólo vamos a crear un consumidor. No me voy a meter en detalles con gSOAP (ya que se me escapa de los artículos) y sólo comentaré aquellos aspectos que nos interesan para integrar Webservices.

Lo primero, es obtener el WSDL de JasperServer. Para ello, y desde una instalación del mismo, se puede obtener sin más que abrir un navegador y solicitar http://servidor:puerto_tomcat/jasperserver/services/repository?wsdl

Bien. gSOAP proporciona dos ejecutables wsdl2h y soapcpp2 para generar los "proxys", esto es, código C++ que encapsula el acceso por webservices. Los ejecutamos tal que así: (INCLUDEGSOAP es una variable que apunta al directorio de includes de gsoap

echo "" > env.h
soapcpp2 -L -C -d../proxy -penv env.h
# Las dos lineas anteriores son para generar un esqueleto de código de acceso a los webservices, que permitan
# una compilación sin problemas.
wsdl2h -nJasperServer -NJasperServer -y -g -I${INCLUDEGSOAP}/ -o JasperServer.h JasperServer.wsdl
soapcpp2 -C -d../proxy -I${INCLUDEGSOAP}/ -n -pjasperserver -qJasperServer JasperServer.h

Con esto se generan una serie de ficheros, .c, .cpp y .h que incluiremos en AbanQ. Concretamente, a flbase.pro, le añadiremos los siguientes ficheros:

-De la distribución de gsoap directamente
stdsoap2.cpp
-Archivos generados con el código anterior
JasperServerClientLib.cpp
envC.cpp
envClient.cpp
stdsoap2.h
JasperServerrepositorySoapBindingProxy.h
JasperServer.nsmap

Ya podemos meter código propio en AbanQ. En el zip que puse días anteriores, viene todo esto integrado. Destaco aquí el código de acceso a los webservices.

Voy a crear un nuevo método en FLUtil que permita, desde QSA, acceder a los webservices. Ese método será tal que así

// dpinelo
bool FLUtil::downloadJasperServerFile(const QString & xmlRequest, const QString & rutaDestino, QString & mensajeSalida)
{
 bool value = false;
 int r;
 std::string result;
 std::string xml = xmlRequest;

 QSettings settings;
 settings.setPath( "InfoSiAL", "FacturaLUX", QSettings::User );
 QString keybase( "/facturalux/lite/jasperserver/" );
 // Lo hago así para garantizar que los objetos existen hasta el final
 QString *userJasperServer = new QString;
 QString *passwordJasperServer = new QString;
 QString *endPointJasperServer = new QString;
 *userJasperServer = settings.readEntry( keybase + "User", "" );
 *passwordJasperServer = settings.readEntry( keybase + "Password", "" );
 *endPointJasperServer = settings.readEntry( keybase + "EndPoint", "" );

 JasperServer::repositorySoapBinding rep;
 // si lo hago sin punteros, esto es peligroso
 rep.soap->userid = (*userJasperServer).ascii();
 rep.soap->passwd = (*passwordJasperServer).ascii();
 rep.endpoint = (*endPointJasperServer).ascii();

 qDebug("Antes de llamar a jasperserver");
 r = rep.JasperServer__runReport(xml, result);
 if ( r == SOAP_OK ) {
 qDebug("Lo ha llamado y es correcto");
 soap_multipart::iterator attachment = rep.soap->mime.begin();
 ++attachment;
 if ( attachment != rep.soap->mime.end() ) {
 saveDocument (*attachment, rutaDestino);
 value = true;
 } else {
 value = false;
 mensajeSalida = result;
 }
 } else {
 qDebug("Hubo un fallo");
 soap_print_fault(rep.soap, stderr);
 value = false;
 }
 delete userJasperServer;
 delete passwordJasperServer;
 return value;    

}

// dpinelo
void FLUtil::saveDocument(const struct soap_multipart & attachment, const QString & path)
{
 QFile file (path);
 file.open ( IO_WriteOnly | IO_Truncate );
 file.writeBlock(attachment.ptr, attachment.size);
 file.close();
}

Listo. ¿Cómo invocar a un informe en JasperServer? Desde QSA es tan sencillo como: Por ejemplo, para imprimir un recibo de proveedor

function oficial_imprimir(codRecibo:String)
{
 var util:FLUtil = new FLUtil;
 var xml:String = "<request operationName=\"runReport\" locale=\"es\">";
 xml = xml + "<argument name=\"RUN_OUTPUT_FORMAT\">PDF</argument>";
 xml = xml + "<resourceDescriptor name=\"\" wsType=\"\" ";
 xml = xml + "uriString=\"/Documentos/Pagare_a_Proveedores/PagareProveedores\" ";
 xml = xml + "isNew=\"false\">";
 xml = xml + "<label>null</label>";
 xml = xml + "<parameter name=\"P_ID_PAGARE\"><![CDATA[100]]></parameter>";
 xml = xml + "<parameter name=\"ANIO\"><![CDATA[09]]></parameter>";
 xml = xml + "</resourceDescriptor>";
 xml = xml + "</request>";
 var rutaDestino:String = "/home/david/prueba.pdf";
 var mensajeSalida:String;
 util.downloadJasperServerFile ( xml, rutaDestino, mensajeSalida);

}

Como veis, construyo un XML con el formato adecuado, según describe JasperServer, indicando los valores de los parámetros del propio report. El archivo se obtiene directamente en PDF (aunque se puede obtener en otros muchos formatos cambiando el RUN_OUTPUT_FORMAT), y por supuesto, podéis ponerle el nombre que querais. (construid adecuadamente rutaDestino).

La integración seía aún mejor en la medida en la que se oculte ese código XML que se construye en QSA, asociando parámetros de JasperReports/JasperServer con columnas de FLSqlCursor. Pero, a mí, este nivel me sirve.

Comentarios (0) Trackbacks (0)

Lo sentimos, los comentarios están cerrados por ahora.

Trackbacks deshabilitados.