| 
 
      
         
      
      
         
            This is version 3.  
            It is not the current version, and thus it cannot be edited.[Back to current version]  
            [Restore this version]
 In my day job, we decided to use a little XMLHttpRequest lovin'
    to populate one drop-down from another. This is my review of JSON-RPC,
    an open source JavaScript library and servlet for simplifying XMLHttpRequest.
    I considered integrate Direct Web Remoting (DWR)
    as well, but its java.net site was down the day I needed it. I started out
    with JSON-RPC 0.7, which caused some conflicts with Commons Validator client-side
    validation. This was fixed in the 0.8 release. JSON-RPC takes a little more
    setup than I care for, but it's pretty easy nonetheless:
 
     Download the 0.8 release from http://oss.metaparadigm.com/jsonrpc-dist/json-rpc-java-0.8.tar.gz.Add the JAR to your project and the webapps/jsonrpc/jsonrpc.js to your
        projects' "scripts" folder. Include this file in your SiteMesh decorator
        or Tiles layout. If you're not using SiteMesh or Tiles, it's high time
        you started.JSON-RPC currently requires that you register each class you want call
        methods on. In our project, I registered a Spring bean (LookupHelper)
        that's a singleton with references to Maps in the ServletContext. Then
        we used JavaScript functions to call JSON-PRC and look up units for
        a plant, and vice versa. I'm not going to put the LookupHelper class
        here - you'll have to trust its methods  return a single String
        or a comma-separated list of Strings. To register this bean with JSON-RPC,
        I created an HttpSessionListener and configured it in web.xml.
 
   
  
   | 
/**
 * UserListener class used to add/remove session attributes when
 * a user first logs in.  Mainly for JavaScript Remote Scripting stuff.
 *
 * @author Matt Raible
 */
 public class UserListener implements HttpSessionListener, HttpSessionAttributeListener
 { private final Log log = LogFactory.getLog(UserListener.class);
 public final static String BRIDGE_KEY = "JSONRPCBridge";
 
 /**
 * Initializes LookupHelper singleton with values needed for lookup
 *
 * @param event the HttpSessionEvent to grab session information from
 */
 public void sessionCreated(HttpSessionEvent event) {
 // Find the JSONRPCBridge for this session or create one
 // if it doesn't exist. Note the bridge must be named BRIDGE_KEY
 // in the HttpSession for the JSONRPCServlet to find it.
 HttpSession session = event.getSession();
 JSONRPCBridge jsonBridge = new JSONRPCBridge();
 jsonBridge.setDebug(true);
 session.setAttribute(BRIDGE_KEY, jsonBridge);
 }
 
 /**
 * Destroys LookupHelper
 *
 * @param event the HttpSessionEvent to grab session information from
 */
 public void sessionDestroyed(HttpSessionEvent event) {
 if (event.getSession() != null) {
 event.getSession().removeAttribute(BRIDGE_KEY);
 }
 }
 
 public void attributeAdded(HttpSessionBindingEvent event) {
 if (event.getName().equals(BRIDGE_KEY)) {
 HttpSession session = event.getSession();
 // register LookupHelper so we can call methods on it
 ApplicationContext ctx =
 WebApplicationContextUtils
 .getWebApplicationContext(session.getServletContext());
 
 // check for null so we don't have to initialize Spring in tests
 if (ctx != null) {
 log.debug("Registering lookupHelper for XmlHttpRequest...");
 JSONRPCBridge jsonBridge =
 (JSONRPCBridge) session.getAttribute(BRIDGE_KEY);
 jsonBridge.registerObject("lookupHelper",
 ctx.getBean("lookupHelper"));
 }
 }
 }
 
 public void attributeRemoved(HttpSessionBindingEvent event) {
 // don't care
 }
 
 public void attributeReplaced(HttpSessionBindingEvent event) {
 // same as attribute added
 attributeAdded(event);
 }
 }
 |  		After this setup was complete, I was able to add the following JavaScript
        to the bottom of my JSP. These are functions that our drop-downs call
        to populate each other, and keep their options in synch.
var jsonurl = "${ctx}/jsonrpc";
    var jsonrpc = null;
    var unitDropDown = document.getElementById("equipmentName");
    function filterUnits(plantDropDown) {
        var plantName = plantDropDown.optionsplantDropDown.selectedIndex.value;
         if (plantName == "") {
            reloadUnits("");
            return;
        }
         try {
            jsonrpc = new JSONRpcClient(jsonurl);
        } catch(e) {
            alert(e);
        }
         // Call a Java method on the server
        var units = jsonrpc.lookupHelper.getUnitsForPlant(plantName);
        setUnits(units);
    }
     function reloadUnits(value) {
         if (value == "") {
            try {
                jsonrpc = new JSONRpcClient(jsonurl);
            } catch(e) {
                alert(e);
            }
             // Call a Java method on the server
            var units = jsonrpc.lookupHelper.getAllUnits();
            setUnits(units);
        }
    }
     function setUnits(units) {
        var unitArray = units.split(",");
         unitDropDown.options.length = 1;  // keep "All" option
        for (i=0; i < unitArray.length; i++) {
            unitDropDown.optionsunitDropDown.options.length =
                new Option(unitArray[i], unitArray[i]);
        }
    }
 The hardest part of using JSON-RPC is setting it up. We only experienced
    minor issues with Commons Validator, but since the JSON-RPC 0.8 release -
    everything has  worked great, on all browsers we need to support. The only
    thing I don't like about this library is that you have to register objects
    for each user's session. I briefly looked at DWR and it looks a little cleaner
    - especially b/c of its Spring integration. The next time we need XMLHttpRequest,
    we'll probably use DRW just to compare the two. 
 
 
 |