Search code examples
javarestdojoxpagesdijit.tree

Stuck trying to use a customRestService and a serviceBean for a dojo Tree in XPages


I'm trying to create a dojo Tree, for the time being with test data. The bean always returns the same. When I put the data in a file inside the nsf Resources, it works. Using the bean, it fails. It displays only the word Continent, and I cannot open and descend the node.

Can someone help me out? I'd appreciate it enormously!

My code, where store2 works, store1 errors out and store0 only shows Continent:

                <xe:restService id="restService1" pathInfo="treeData">
                    <xe:this.service>
                        <xe:customRestService serviceBean="com.sefip.TreeData" requestContentType="application/json" requestVar="tree"></xe:customRestService>
                    </xe:this.service>
                </xe:restService>
                <!--
                    xp:text disableTheme="true" value="#{javascript:getBoxValue(compositeData.boxName)}" styleClass="readonly" style="margin-top:2px">
                    <xp:this.rendered><![CDATA[#{javascript:getBoxValue(compositeData.boxName)}]]></xp:this.rendered> </xp:text> <xp:div id="boxTree"
                    dojoType="dijit.Tree"></xp:div
                -->

                <xp:scriptBlock id="scriptBlock2">
                    <xp:this.value><![CDATA[
    dojo.require("dojox.data.JsonRestStore");
    dojo.require("dojo.store.JsonRest");
    dojo.require("dojo.data.ItemFileReadStore");
    dojo.require("dijit.tree.ForestStoreModel");
    dojo.require("dijit.Tree");

    dojo.addOnLoad(function() {

// Create a data store to retrieve data from

        var store0 = new dojox.data.JsonRestStore({
            //url: "countries.json"
            target: "aCRM2.xsp/treeData/",
            labelAttribute: "name"
        });

        var store1 = new dojo.store.JsonRest({
            target: "aCRM2.xsp/treeData/",
            labelAttribute: "name"
        });

        var store2 = new dojo.data.ItemFileReadStore({
            url: "countries.json"
        });


// secondly we create a treeModel. 
        var treeModel = new dijit.tree.ForestStoreModel({
            store: store0,
            query: {type: "continent"},
            rootId: "root",
            rootLabel: "Continents",
            childrenAttrs: ["children"]
        });

// Last but not least we create a new instance of our tree. 
        var tree= new dijit.Tree({
            model: treeModel
        },
        "#{id:treeOne}");
    });
    ]]></xp:this.value>
                </xp:scriptBlock>

                <!-- The domnode we will use to render the tree -->
                <xp:div id="treeOne" />

            </xp:div>

The countries.json contains:

{
    "items" : [{
            "id" : "EU",
            "children" : [{
                    "_reference" : "NL"
                }
            ],
            "type" : "continent",
            "name" : "Europe"
        }, {
            "id" : "NL",
            "type" : "country",
            "name" : "Netherlands"
        }
    ],
    "label" : "name",
    "identifier" : "id"
}

The bean generates exactly the same, but for completeness' sake I'll add the code here:

package com.sefip;

import java.io.IOException;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.ibm.commons.util.io.json.JsonException;
import com.ibm.commons.util.io.json.JsonGenerator;
import com.ibm.domino.services.ServiceException;
import com.ibm.domino.services.rest.RestServiceEngine;
import com.ibm.jscript.InterpretException;
import com.ibm.jscript.JSContext;
import com.ibm.jscript.json.JsonJavaScriptFactory;
import com.ibm.jscript.std.ArrayObject;
import com.ibm.jscript.std.ObjectObject;
import com.ibm.jscript.types.FBSUtility;
import com.ibm.xsp.extlib.component.rest.CustomService;
import com.ibm.xsp.extlib.component.rest.CustomServiceBean;
import com.ibm.xsp.util.JavaScriptUtil;

public class TreeData extends CustomServiceBean {

    @Override
    public void renderService(CustomService service, RestServiceEngine engine) throws ServiceException {

        HttpServletRequest request = engine.getHttpRequest();
        HttpServletResponse response = engine.getHttpResponse();
        String method = request.getMethod();

        response.setHeader("Content-Type", "application/json; charset=UTF-8");

        if (method.equals("GET")) {
            this.get(engine);
        } else if (method.equals("POST")) {
            this.post(engine, request);
        } else {
            this.other(engine);
        }
    }

    public void get(RestServiceEngine engine) {
        HttpServletResponse response = engine.getHttpResponse();
        try {
            JSContext jsContext = JavaScriptUtil.getJSContext();
            JsonJavaScriptFactory factory = new JsonJavaScriptFactory(jsContext);
            String json = null;
            ObjectObject returnJSON = new ObjectObject();
            returnJSON.put("identifier", FBSUtility.wrap("id"));
            returnJSON.put("label", FBSUtility.wrap("name"));
            ArrayObject countries = new ArrayObject();
            ObjectObject continent = new ObjectObject();
            continent.put("id", FBSUtility.wrap("EU"));
            continent.put("name", FBSUtility.wrap("Europe"));
            continent.put("type", FBSUtility.wrap("continent"));
            ArrayObject children = new ArrayObject();
            ObjectObject child = new ObjectObject();
            child.put("_reference", FBSUtility.wrap("NL"));
            children.addArrayValue(child);
            continent.put("children", children);
            countries.addArrayValue(continent);
            ObjectObject country = new ObjectObject();
            country.put("id", FBSUtility.wrap("NL"));
            country.put("name", FBSUtility.wrap("Netherlands"));
            country.put("type", FBSUtility.wrap("country"));
            countries.addArrayValue(country);
            returnJSON.put("items", countries);
            UserData.get().addLog("call generator");
            json = JsonGenerator.toJson(factory, returnJSON);
            UserData.get().addLog(json);
            response.getWriter().write(json);
            response.getWriter().close();
            return;
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (JsonException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InterpretException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void post(RestServiceEngine engine, HttpServletRequest request) {
        HttpServletResponse response = engine.getHttpResponse();
        Map parameters = request.getParameterMap();
        try {
            response.getWriter().write("post()");
            response.getWriter().write(request.getParameter("form"));
            String[] form = (String[]) parameters.get("form");
            String val = form[0];
            response.getWriter().write(val);
            response.getWriter().close();
        } catch (Exception e) {
            // TODO: handle exception
        }

    }

    public void other(RestServiceEngine engine) {
        HttpServletResponse response = engine.getHttpResponse();
        try {
            response.getWriter().write("other()");
            response.getWriter().close();
            return;
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

All this is largely based on the work done by Jeroen Somhorst and others, see http://www.jeroensomhorst.eu/uncategorized/viewpanel-vs-dijit-tree-part-1/ and part-2.

PS Dank je, Jeroen, maar waar is part-3?? ;-)


Solution

  • Finally found a solution.

    It turns out that the structure for a JsonRestStore should be a nested array with objects and children, like this:

    [{
        "id" : "EU",
        "children" : [{
            "id" : "NL",
            "type" : "country",
            "name" : "Netherlands"
            }],
        "type" : "continent",
        "name" : "Europe"
    }]
    

    Plain and simple...

    Thanks Jeroen, for the link, the comments in there showed me this way.