1

I need to read with the function SSJS fromJson() a URL. For example the Data access API for a Notes View

http://{host}/{database}/api/data/collections/name/{name}

How can I do this ?

P.S I think (I don't know if is true) that if I use Java code (for example the class URLReader from this blogger, I lose authors/readers functionality because is my server and not the current user that execute the reading of the stream?

I'll explain why I'm trying to understand this...

I need to use this plugin JQuery Jquery Data Tables in my app. I need a complete Server-side processing because I have over 10.000 documents for any view. This jQueryPlugin send a parameters to a specif URL (I think my XAgent) so that I think to create a XAgent that read this parameter and parsing a JSON API Data for the output. This because I need a fasted response.

The solution of Oliver Busse it very slow because load all entries of my view in a JSON (I have many entries) and I wait 30/40 seconds for this operation

Daniele Grillo
  • 1,011
  • 4
  • 13
  • 31
  • 1
    If you're using an XPages SSJS context to get the data, why not just keep the server-side calls on the server-side (without forcing yourself through the re-interpretation of a client-side, URI call to the Domino Data Service)? It seems to me to be a layer of complication to an otherwise normal cross-NSF call to establish a handle on a View; especially as you raise concerns about Reader/Author fields (and rights for the user relating to their NotesSession). – Eric McCormick Nov 05 '15 at 14:17
  • @Eric: I'll update my post. thank you – Daniele Grillo Nov 05 '15 at 14:28
  • That definitely makes more sense now that I know you're pre-processing another source's response for the pagination. I would however recommend you consider using the _count_ and _startFrom_ parameters for the Domino Data Service, so you could potentially skip the additional server-side processing. The [parameters available are outlined in the documentation](http://infolib.lotus.com/resources/domino/8.5.3/doc/designer_up1/en_us/DominoDataService.html#ddapi_ref_viewfolderentries). – Eric McCormick Nov 05 '15 at 14:31
  • Yes @Eric thank you very mich! – Daniele Grillo Nov 05 '15 at 14:33

2 Answers2

2

I gather from the PS that you're specifically looking to fetch JSON on the server from itself, while retaining user authentication information. Sven's post there does a bit of that, but I think that the most reliable way would be to grab the Authorization and Cookie headers from the request and then pass them along in your URL request. This answer has a good basis for doing this with Java. You could expand that to do something like this (which, granted, I haven't tested, but it's a starting point):

    HttpServletRequest req = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
    String authorization = req.getHeader("Authorization");
    String cookie = req.getHeader("Cookie");

    URL myURL = new URL("http://foo.com");
    HttpURLConnection myURLConnection = (HttpURLConnection)myURL.openConnection();
    if(StringUtil.isNotEmpty(authorization)) {
        myURLConnection.setRequestProperty("Authorization", authorization);
    }
    if(StringUtil.isNotEmpty(cookie)) {
        myURLConnection.setRequestProperty("Cookie", cookie);
    }
    myURLConnection.setRequestMethod("GET");
    myURLConnection.setDoInput(true);
    myURLConnection.setDoOutput(true);
    myURLConnection.connect();
    InputStream is = null;
    try {
        is = myURLConnection.getInputStream();
        String result = StreamUtil.readString(is);
    } finally {
        StreamUtil.close(is);
        myURLConnection.disconnect();
    }

Ideally, you would also fetch the server host name, protocol, and port from the request.

Eric's comment is also wise: if this is something you can do with the normal classes, that's going to be more flexible and less problem-prone, due to how fiddly server-self HTTP calls can be.

Community
  • 1
  • 1
Jesse Gallagher
  • 4,461
  • 13
  • 11
2

As I mentioned in my comment, this approach forces that your call go through a client-side call to the Domino Data Service and otherwise complicates a normal handle to establish on a View (and it's contents) via a cross-NSF call (e.g.- var vwEnt:ViewEntryCollection = session.getDatabase("serverName", "path/myDb.nsf").getView("viewName").getAllEntries();).

As a blog post of mine previously outlines, you can definitely achieve this as Jesse's answer (curse you fast typer Jesse!) outlines. Something I include in my "grab bag" of tools is a Java class that's a starting point for getting JSON formatted content. Here's the link (here's one with basic authorization in a request header) and the class I generally start from:

package com.eric.awesome;

import java.net.URL;
import java.net.URLConnection;
import java.io.BufferedReader;
import com.google.gson.*;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.net.MalformedURLException;
import org.apache.commons.validator.routines.*;

/**
 * Class with a single, public, static method to provide a  REST consumer
 * which returns data as a JsonObject.
 * 
 * @author Eric McCormick, @edm00se
 * 
 */
public class CustJsonConsumer {
    /**
     * Method for receiving HTTP JSON GET request against a RESTful URL data source.
     * 
     * @param myUrlStr the URL of the REST endpoint
     * @return JsonObject containing the data from the REST response.
     * @throws IOException
     * @throws MalformedURLException
     * @throws ParseException 
     */
    public static JsonObject GetMyRestData( String myUrlStr ) throws IOException, MalformedURLException {
        JsonObject myRestData = new JsonObject();
        try{

            UrlValidator defaultValidator = new UrlValidator();
            if(defaultValidator.isValid(myUrlStr)){

                URL myUrl = new URL(myUrlStr);
                URLConnection urlCon = myUrl.openConnection();
                urlCon.setConnectTimeout(5000);
                InputStream is = urlCon.getInputStream();
                InputStreamReader isR = new InputStreamReader(is);
                BufferedReader reader = new BufferedReader(isR);
                StringBuffer buffer = new StringBuffer();
                String line = "";
                while( (line = reader.readLine()) != null ){
                    buffer.append(line);
                }
                reader.close();
                JsonParser parser = new JsonParser();
                myRestData = (JsonObject) parser.parse(buffer.toString());

                return myRestData;

            }else{
                myRestData.addProperty("error", "URL failed validation by Apache Commmons URL Validator");
                return myRestData;
            }
        }catch( MalformedURLException e ){
            e.printStackTrace();
            myRestData.addProperty("error", e.toString());
            return myRestData;
        }catch( IOException e ){
            e.printStackTrace();
            myRestData.addProperty("error", e.toString());
            return myRestData;
        }
    }
}

To invoke from SSJS as a POJO, you would want do something like:

importPackage(com.eric.awesome);

var urlStr = "http://{host}/{database}/api/data/collections/name/{name}";
var myStuff:JsonObject = CustJsonConsumer.GetMyRestData(urlStr);
Eric McCormick
  • 2,716
  • 2
  • 19
  • 37