Raible's Wiki

Raible Designs
Wiki Home
News
Recent Changes

AppFuse

Homepage
  - Korean
  - Chinese
  - Italian
  - Japanese

QuickStart Guide
  - Chinese
  - French
  - German
  - Italian
  - Korean
  - Portuguese
  - Spanish
  - Japanese

User Guide
  - Korean
  - Chinese

Tutorials
  - Chinese
  - German
  - Italian
  - Korean
  - Portuguese
  - Spanish

FAQ
  - Korean

Latest Downloads

Other Applications

Struts Resume
Security Example
Struts Menu

Set your name in
UserPreferences


Referenced by
...nobody




JSPWiki v2.2.33

[RSS]


Hide Menu

Sandbox


Difference between version 33 and version 2:

At line 1 removed 23 lines.
In my day job, we decided to use a little <a href="http://raibledesigns.com/page/rd?anchor=xmlhttprequest">XMLHttpRequest</a> lovin'
to populate one drop-down from another. This is my review of <a href="http://oss.metaparadigm.com/jsonrpc/">JSON-RPC</a>,
an open source JavaScript library and servlet for simplifying XMLHttpRequest.
I considered integrate <a href="https://dwr.dev.java.net/">Direct Web Remoting</a> (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:</p>
<ol>
<li> Download the 0.8 release from <a href="http://oss.metaparadigm.com/jsonrpc-dist/json-rpc-java-0.8.tar.gz">http://oss.metaparadigm.com/jsonrpc-dist/json-rpc-java-0.8.tar.gz</a>.</li>
<li>Add the JAR to your project and the webapps/jsonrpc/jsonrpc.js to your
projects' &quot;scripts&quot; folder. Include this file in your <a href="http://www.opensympony.com/sitemesh">SiteMesh</a> decorator
or <a href="http://struts.apache.org/userGuide/dev_tiles.html">Tiles</a> layout. If you're not using SiteMesh or Tiles, it's high time
you started.</li>
<li>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.
At line 26 changed 127 lines.
/**
* 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);
}
}
]}
</li>
<li>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.
<pre>
var jsonurl = "${ctx}/jsonrpc";
var jsonrpc = null;
var unitDropDown = document.getElementById("equipmentName");
function filterUnits(plantDropDown) {
var plantName = plantDropDown.options[plantDropDown.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.options[unitDropDown.options.length] =
new Option(unitArray[[i], unitArray[[i]);
}
}
</pre>
</li>
</ol>
<p>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.
class MyTagLib{
def isAdmin= { attrs, body->
def user = attrs["user"]
if (user!= null && checkUserPrivs(user))
body()
}
}
}]

Back to Sandbox, or to the Page History.