Etiqueta: url

birt – create report from JSON data sent as parameter

Normally you would construct your reports from data that is already stored somewhere, it could be a database, a file or something else. I was required to build a preview of a report -that is, before the data were inserted- so that the user can confirm the information before making the request.

Since the data is sent in JSON format already, I thought I could elaborate a report from this same data.

{
    "averiguacion":null, 
    "actores":[
        {
            "genero":"F", 
            "fechaNacimiento":"1980-05-13", 
            "origenIngreso":"FORMAL", 
            "idMunicipio":"22014", 
            "idEstado":"22", 
            "idColonia":"22014010800001", 
            "nombre":"ROSA", 
            "itemId":1, 
            "apellidos":"MENDEZ", 
            "idLugarNacimiento":3, 
            "ingresoMensual":2500, 
            "calle":"SIN REGISTRO", 
            "numero":0, 
            "codigoPostal":0, 
            "direccion":"LINDAVISTA", 
            "principal":"X"
        }
    ], 
    "demandados":[
        {
            "genero":"M", 
            "fechaNacimiento":"2019-05-13", 
            "origenIngreso":"FORMAL", 
            "idMunicipio":"22014", 
            "idEstado":"22", 
            "idColonia":"22014010800001", 
            "nombre":"JORGE", 
            "itemId":1, 
            "apellidos":"HERNANDEZ", 
            "calle":"SIN REGISTRO", 
            "numero":0, 
            "codigoPostal":0, 
            "direccion":"LOMA BONITA", 
            "principal":"X"
        }
    ], 
    "terceros":[
    ], 
    "observaciones":"LA SOLICITANTE VIENE GOLPEADA", 
    "compareciente":"VICTIMA", 
    "anexos":[
        {
            "__module":{
            }, 
            "tipo":"OFRECIDO", 
            "descripcion":"IDENTIFICACION OFICIAL"
        }, 
        {
            "__module":{
            }, 
            "tipo":"OFRECIDO", 
            "descripcion":"ACTA DE MATRIMONIO"
        }
    ], 
    "medidasSolicitadas":[
        {
            "nombre":"ARRAIGO", 
            "id":17, 
            "_selection_34":true
        }, 
        {
            "nombre":"CUSTODIA DE INFANTES", 
            "id":8, 
            "_selection_34":true
        }
    ], 
    "domicilioDesahogo":"LINDAVISTA", 
    "horarioDomicilioDemandado":"LUNES A VIERNES DESPUES DE LAS 16HRS"
}

We are going to need some variables to store counts and serialize the JSON into an object, let’s select the Outline tab and click on the report name, then in the script tab let’s define the following variables -which will be accessible from the fetch events we’ll see later-

Screenshot from 2019-05-15 12-43-23

var jsonPayload;
var countActores = 0;
var countDemandado = 0;
var countMedidas = 0;
var countAnexos = 0;

Create a new scripted data source, let’s call it ‘jsonPayload’. Then add a new report parameter called ‘payload’ of type String and optionally establish a default value, i.e. {"actores":[{"nombre":"ROSA"}]}. Select the jsonPayload data source and in the Script tab in the ‘open’ event we’ll serialize the JSON data into the jsonPayload variable we define earlier

jsonPayload = eval('(' + params['payload'] + ')');

With this, you could insert a DynamicText anywhere in your report to access the properties in jsonPayload object. Just enter the expression in the Expression builder like so

Screenshot from 2019-05-15 12-55-55

jsonPayload.observaciones

Now, let’s create a new data set, using the jsonPayload scripted datasource and define the columns corresponding to the JSON data, for each array list property that we have in our JSON, i.e. actores

Screenshot from 2019-05-15 13-10-43

Let’s call it jsonActores and in the fetch event in the script tab for this dataset, let’s read the values from our jsonPayload object. This method returns true if there’s more data to load and false otherwise

if(countActores < jsonPayload.actores.length){
    row['nombre'] = jsonPayload.actores[countActores].nombre;
    row['apellidos'] = jsonPayload.actores[countActores].apellidos;
    row['fechaNacimiento'] = jsonPayload.actores[countActores].fechaNacimiento;
    row['genero'] = jsonPayload.actores[countActores].genero;
    row['lugarNacimiento'] = jsonPayload.actores[countActores].lugarNacimiento;
    row['origenIngreso'] = jsonPayload.actores[countActores].origenIngreso;
    row['ingresoMensual'] = jsonPayload.actores[countActores].ingresoMensual;
    countActores++;
    return true;
} else {
    return false;
}

that’s it, now we can drag and drop our dataset in the report as any other.

You can pass the parameter, to an instance of the BIRT report viewer for example, in the URL like so

http://127.0.0.1:57045/viewer/run?__report=Preview.rptdesign&__format=pdf&payload={…json data…}

sources:
https://stackoverflow.com/questions/30349864/use-json-as-a-scripted-data-set-in-birt

Use JSON as a Scripted Data Set

Anuncios

angularjs – bootstrap tabs route conflict

In an old angularjs app where we used bootstrap 2.3.2 we wanted to implement a tab component to separate results from different sources.

We added a tab component as shown in the docs

<ul class="nav nav-tabs">
  <li><a href="#home" data-toggle="tab">Home</a></li>
  <li><a href="#profile" data-toggle="tab">Profile</a></li>
  <li><a href="#messages" data-toggle="tab">Messages</a></li>
  <li><a href="#settings" data-toggle="tab">Settings</a></li>
</ul>

<div class="tab-content">
  <div class="tab-pane active" id="home">...</div>
  <div class="tab-pane" id="profile">...</div>
  <div class="tab-pane" id="messages">...</div>
  <div class="tab-pane" id="settings">...</div>
</div>

but it navigated away from the page (state), instead of switching tabs. The problem is the angularjs routing mechanism, it uses bang hashtag navigation -it means it uses the url address to know which route is active, actual navigation doesn’t happen, remember it is SPA (Single Page Application)-
So, in the previous example when the profile tab is clicked it changed the url to http://myapp/index.html#/profile because of the href we used.

The solution is quite simple and I found it here, just change the href attributes to data-target and add an empty href attribute (to change the cursor as it would do with links).

<ul class="nav nav-tabs">
  <li><a href="" data-target="#home" data-toggle="tab">Home</a></li>
  <li><a href="" data-target="#profile" data-toggle="tab">Profile</a></li>
  <li><a href="" data-target="#messages" data-toggle="tab">Messages</a></li>
  <li><a href="" data-target="#settings" data-toggle="tab">Settings</a></li>
</ul>

<div class="tab-content">
  <div class="tab-pane active" id="home">...</div>
  <div class="tab-pane" id="profile">...</div>
  <div class="tab-pane" id="messages">...</div>
  <div class="tab-pane" id="settings">...</div>
</div>

birt report drill down url window location base path problem

You can navigate to the details of a certain data category in a BIRT report using the hyperlink property of an element and use the drill down option to configure it.

Selection_007

Hyperlink Options _006

the problem for us was that when deploying the report to an instance of the ReportViewer it added some wrong path prefix to the report path variable ‘__report’.

So we had to construct the path ourselves. First change the drill-trough option to URI, and the Location to javascript syntax.

We tried to access the window object from a script in the report (since the scripts are javascript) and use it to find out the base url and path, but it failed complaining that ‘window’ was not defined. I suppose you can’t access the window object, I couldn’t find one.

importPackage(Packages.java.text);
sdf = new SimpleDateFormat('yyyy-MM-dd');

window.location.origin + window.location.pathname +
'?__format=pdf&__report=report/tsj/DetallesIndicadores/DetalleCarpetasIniciadas.rptdesign' +
'&desde=' + sdf.format(params['desde']) +
'&hasta=' + sdf.format(params['hasta'])

But it turns out, as I discovered through this forum post, you can use the report context object to access the HttpServletRequest which we can use to construct our URL.

Then you just have to format and add your parameters to the URL.

Ours ended up like this

importPackage(Packages.java.text);
sdf = new SimpleDateFormat('yyyy-MM-dd');

reportContext.getHttpServletRequest().getRequestURL().toString() +
'?__format=pdf&__report=report/tsj/DetallesIndicadores/DetalleCarpetasIniciadas.rptdesign' +
'&desde=' + sdf.format(params['desde']) +
'&hasta=' + sdf.format(params['hasta'])

remember the last line is returned as the value for our URL, in this case the concatenation of our values.

sources:
https://www.eclipse.org/forums/index.php/m/1235339/?srch=window.location#msg_1235339
https://help.eclipse.org/mars/index.jsp?topic=%2Forg.eclipse.birt.doc.isv%2Fenginescript%2Fapi%2Forg%2Feclipse%2Fbirt%2Freport%2Fengine%2Fapi%2Fscript%2FIReportContext.html
https://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/http/HttpServletRequest.html
https://stackoverflow.com/questions/1629102/root-url-of-the-servlet

Spring – Utilizar una expresión regular para especificar la ruta del controlador

Supongamos que tenemos un servicio web para obtener un listado de facturas de una fecha específica en la siguiente url

api.server.com/facturas/2014-11-24

nuestro controlador sería

    @RequestMapping(value = "/facturas/{fecha}", method = RequestMethod.GET)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public List<Factura> searchFacturas(@PathVariable Date fecha){
        List<Factura> facturas = service.searchFacturas(fecha);
        return facturas;
    }

Ya vimos como convertir parámetros de tipo fecha

Pero que pasa si necesitamos crear otro servicio para obtener las facturas de un cliente con la siguiente URL

api.server.com/facturas/CQRO01

si implementamos el servicio tal como el anterior tendríamos un conflicto con la URL ya que no le hemos indicado de alguna forma como distinguir entre un id de cliente y una fecha. Para distinguir podemos utilizar expresiones regulares

    @RequestMapping(value = "/facturas/{fecha:d{4}-d{2}-d{2}}", method = RequestMethod.GET)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public List<Factura> searchFacturas(@PathVariable Date fecha){
        List<Factura> facturas = service.searchFacturas(fecha);
        return facturas;
    }

    @RequestMapping(value = "/facturas/{cliente:w{6}}", method = RequestMethod.GET)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public List<Factura> searchFacturas(@PathVariable String cliente){
        List<Factura> facturas = service.searchFacturas(cliente);
        return facturas;
    }

Fuentes:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-requestmapping-uri-templates-regex
http://stackoverflow.com/questions/17889604/how-to-use-a-regex-path-mapper-variable-in-a-requestmapping
http://stackoverflow.com/questions/18422368/regex-in-spring-controller

ionic – Navegar a otra página pasando parámetros en la url

A diferencia de AngularJS, ionic utiliza el módulo ui-router en vez de ngRoute para el mecanismo de enrutamiento de las páginas.
En nuestra configuración tendremos estados en vez de rutas. Por ejemplo,

phonecatApp.config(['$routeProvider',
  function($routeProvider) {
    $routeProvider.
      when('/phones', {
        templateUrl: 'partials/phone-list.html',
        controller: 'PhoneListCtrl'
      }).
      when('/phones/:phoneId', {
        templateUrl: 'partials/phone-detail.html',
        controller: 'PhoneDetailCtrl'
      }).
      otherwise({
        redirectTo: '/phones'
      });
  }]);

se convertiría en

    phonecatApp.config(function ($stateProvider, $urlRouterProvider) {
        $stateProvider

            .state('phones', {
                url: '/phones',
                templateUrl: 'partials/phone-list.html',
                controller: 'PhoneListCtrl'
            })

            .state('phones.detail', {
                url: '/:phoneId',
                templateUrl: 'partials/phone-detail.html',
                controller: 'PhoneDetailCtrl'
            })

        $urlRouterProvider.otherwise('/phones')
    })

Y para navegar a otra página, supongamos que tenemos un botón en nuestra plantilla

<button class="button button-block button-positive" ng-click="goTo(phoneId)">
                Detail
</button>

nuestro controlador quedaría

    .controller('PhoneListCtrl', ['$scope', '$state', function($scope, $state){
        $scope.goTo = function(phoneId){
            $state.go('phones.detail', {phoneId: phoneId})
        }
    }])

notesé el paso del parámetro ‘phoneId’

Fuentes:

Java – Ambiente de producción y desarrollo

Lo más común es desarrolllar nuestras aplicaciones en un ambiente de desarrollo, es decir, utilizar servidores de prueba para después implementarlo en un ambiente de produción. Si el código de tu proyecto se encuentra en un sistema de control de código (git, svn, etc.) es díficil, si no tedioso, cambiar entre un ambiente y otro. Tienes que modificar los archivos de configuración para que se conecte a la base de datos de producción cada vez que actualizas el sistema y debes tener cuidado de no incluir en el control de código las conexiones de prueba o visceversa.

Para resolver este problema podemos utilizar JNDI, pero se vuelve complicado el mantener un entorno replicado en nuestra máquina de desarrollador. Eixsten plataformas para desarrollar y ejecutar aplicaciones web de forma escalable -tales como- Heroku, Google App Engine o Microsoft Azure. Para resolver este problema de contextos, Heroku ha optado por utilizar variables de ambiente para cambiar entre el contexto de desarrollo y el de producción.

Esta solución me pareció adecuada y decidí implementarla en un proyecto Java. Realmente es muy sencillo, normalmente creamos una conexión a la base de datos de la siguiente forma:

DriverManager.getConnection(dbUrl, dbUser,dbPassword);

Necesitamos 3 cosas: url a la base de datos, usuario y contraseña.
Opcionalmente podemos incluir el usuario y contraseña en la URL de la base de datos si el controlador lo permite.En el caso de Oracle es de la siguiente manera:

jdbc:oracle:thin:[USER/PASSWORD]@[HOST][:PORT]:SID
jdbc:oracle:thin:[USER/PASSWORD]@//[HOST][:PORT]/SERVICE

Para leer la configuración de las variables de ambiente sería

DriverManager.getConnection(System.getenv(“DATABASE_URL”));

En nuestro caso utilizamos diferentes conexiones de acuerdo al usuario y la base de datos, por lo que seguimos una nomenclatura de la siguiente manera

USUARIO_AT_DATABASE

así por ejemplo, podríamos conectarnos a distintas bases de datos

   DriverManager.getConnection(System.getenv("RH_AT_QUERETARO"));
   DriverManager.getConnection(System.getenv("RH_AT_AMEALCO"));
   DriverManager.getConnection(System.getenv("USRCIVQRO_AT_QUERETARO"));

Por último necesitas configurar estas variables de ambiente en tu sistema operativo.

En Ubuntu lo puedes hacer de diferentes formas.
A mi me funcionó creando un archivo env.sh en la carpeta /etc/profile.d

   #!/usr/bin/bash
   export RH_AT_CENTRO_DE_JUSTICIA=jdbc:oracle:thin:rh/secret@127.0.0.1:1521:dbtest
   export COMPRAS_AT_AMEALCO=jdbc:oracle:thin:compras/secret@127.0.0.1:1521:dbtest

Fuentes:
https://devcenter.heroku.com/articles/heroku-postgresql#connecting-in-java
http://stackoverflow.com/questions/5547224/username-password-in-jdbc-connection-url
https://help.ubuntu.com/community/EnvironmentVariables
http://askubuntu.com/questions/307023/command-not-working-in-profile

Linux – Descargar archivos de una URL a partir de un archivo CSV

wget
wget

Para realizar esta tarea utilicé el comando wget. Para especificar o dar formato a la URL encontré 3 opciones: awk, sed y el mismo comando wget.

awk me pareció el más complejo por eso no lo utilicé. La opción wget -i es la más senciclla pero necesitas tener en el archivo las url’s  fijas de los archivos que quieres descargar, yo tenía una URL dinámica para cada archivo. El comando sed me pareció la opción mas viable para resolver mi problema.

La url de los archivos que quería descargar era

http://127.0.0.1:8080/ReportViewer/run?__format=xls&__report=rptInformeMensual.rptdesign&REPORTE=ID_REPORTE

la variable ID_REPORTE la tenía en un archivo CSV de la siguiente manera

35ac0194-6992-402d-aa8e-79ae9866b90a COMPRAS
66fbf25f-74ab-412c-abf9-87769582cf48 DIRECCIÓN DE PSICOLOGÍA
7b781032-e529-4d2d-b497-b47b39195688 DIRECCIÓN JURÍDICA
76612f8a-944d-4ce3-bfa6-e9a83a787480 ACTIVO FIJO
...

la primer columna es el id del reporte y la segunda la descripción.

El comando que utilicé fue el siguiente

sed 's/\(.*\)\t\(.*$\)/"http:\/\/127.0.0.1:8080\/ReportViewer\/run?__format=xls\&__report=rptInformeMensual\.rptdesign\&REPORTE=\1" -O "\2\.xls"/' reportes.txt | xargs -l1 wget

Puedes ejecutar sólo la primera parte del comando para revisar que estas pasando los parámetros correctos a wget.

sed recibe como parámetro una cadena con el formato ‘s/regex/substitution/’, regex es una expresión regular que en nuestro caso es el texto hasta el carácter de tabulación ‘\t’ y para el segundo grupo el texto restante hasta el fin de línea indicado por ‘$’. En la expresión regular y en la cadena de substitución hay que tener cuidado de escapar los carácteres especiales como la diagonal, el punto y el ampersand. Los grupos de la expresión regular los insertamos de acuerdo a su posición en la exresión regular \1, \2, \3, etc.

Fuentes:
http://askubuntu.com/questions/103623/download-files-from-a-list
http://unix.stackexchange.com/questions/41598/using-csv-line-as-command-parameters
http://unix.stackexchange.com/questions/32907/what-characters-do-i-need-to-escape-when-using-sed-in-a-sh-script