Thursday, March 12, 2015

How to access NextReports Server web services in your application

NextReports Server has a number of web services. These can be found in ro.nextreports.server.api. NextReports uses Jersey web services so in any web service class users can see @Path and @QueryParam annotations to know how to create the url. All urls start with:
http://<server_ip>:<server_port>/nextreports-server/api

If users need to access these services using java code, then a client for these services already exists and can be found in ro.nextreports.server.api.client. Inside designer installation folder in lib there is nextreports-server-client-8.0.jar library which can be used. To see how it is used in designer  you can look in ro.nextreports.designer.wizpublish . Here is the code used to publish/download report/charts to/from server. (it involves also how to authenticate, to get list of entities from server, create a folder in server structure and more)

For example to authenticate you have to do the following with the root url previously shown:

WebServiceClient client = new WebServiceClient();   
client.setServer(url);
client.setUsername(userTextField.getText());
client.setPassword(new String(passField.getPassword()));
client.setPasswordEncoder(new Md5PasswordEncoder());

boolean authorized = false;
try {
      authorized = client.isAuthorized();            
} catch (Exception e) {
     // connection error
     e.printStackTrace();
     return false;
}

To get entities from server:

List<EntityMetaData> entities = client.getEntities(folderPath);

This method sets the server url path by appending to base api url "storage/getEntities/" and then the folder path. There are some root constants used to create folderPath like /reports, /charts, /dataSources.

If you want to call Next web services  from Javascript/JQuery and get reports from a path, you have also to be authenticated. Next example uses two javascript libraries:

Base64 encoder (jquery.base64.js) : https://github.com/carlo/jquery-base64/archive/master.zip
MD5 generation (core-min.js and md5-min.js) : https://code.google.com/p/crypto-js/#MD5

This example does an ajax get to obtain the list of reports from root /reports path. Request header contains an Authorization object. On success the list of entities (path and type) is shown in a html list.

<html>
    <head>
       <title>NextReports Server JQuery Test</title>
       <script src="jquery-1.10.2.min.js" type="text/javascript"></script>
       <script src="jquery.base64.js" type="text/javascript"></script>
       <script src="core-min.js" type="text/javascript"></script>
       <script src="md5-min.js" type="text/javascript"></script>
       <script>       
             var serverPath = "/reports";    
             var username="admin";
             var password="1";       
             var passwordHash = CryptoJS.MD5("1");
             var base64 = $.base64.encode( username + ":" + passwordHash );                
             $.ajax( {               
                    type: "GET",
                    url : 'http://localhost:8081/nextreports-server/api/storage/getEntities?path=' + serverPath,
                    dataType : "xml",               
                    beforeSend : function(xhr) {            
                            console.log(base64);
                            xhr.setRequestHeader('Authorization', 'Basic ' + base64);
                    },        
                   error : function(xhr, ajaxOptions, thrownError) {
                            console.log("error");            
                            alert(thrownError);
                   },
                   success : function(data) {            
                            console.log("success");            
                            console.log(data);        
                            $('#title').append(serverPath);     
                            var paths = data.getElementsByTagName("path");
                            var types = data.getElementsByTagName("type");
                            var root = $("#list");
                            for (var i=0; i<paths.length; i++) {
                                  var type = "";
                                  if (types[i].textContent === "1") {
                                      type = "folder";
                                  } else if (types[i].textContent === "3") {
                                      type = "next-report";
                                  } else if (types[i].textContent === "4") {
                                      type = "jasper-report";
                                  }                  
                                  root.append('<li>'+paths[i].textContent+ ' (' + type + ')</li>');
                           }
                   }
         });
    </script>
    </head>    
    <body>
        <div>
            <span id="title">List of reports from path: </span>
            <ul id="list"></ul>
        </div>
    </body>

To be able to run this example you must be in the same domain as server, otherwise a cross domain exception will be seen in console. From NextReports Server 8.1 inside web.xml for jersey.springServlet you can uncomment the following to allow for cross domain testing calls (please be sure to comment it back after you make your tests):

       <init-param>
            <param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
            <param-value>ro.nextreports.server.web.core.ResponseCorsFilter</param-value>
        </init-param>       

No comments: