portals-jetspeed-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From David Sean Taylor <da...@bluesunrise.com>
Subject Re: Ajax
Date Thu, 24 Nov 2005 16:05:55 GMT
Christophe Lombart wrote:
> Hi all,
> 
> What is the current status of the Ajax support in J2 ?   I didn't
> follow all messages about this topic and I'm wondering what we can do
> with Ajax within J2.
> 
> Are there some tools to use Ajax in my own portlet  ? or is it better
> to use other frameworks like Taconite, dwr, ...       For example, I
> would like to build a dynamic tree view which can retrieve subitems
> only when it is needed.
> 
Funny that you ask, thats what Roger and I plan to work on next week.
And yes, there is an AJAX pipeline in Jetspeed-2 to handle AJAX request 
through the Jetspeed pipeline.
We're currently working on a Layout API for Javascript customization.Its 
in subversion trunk under the portal component:

org.apache.jetspeed.ajax.AjaxRequestServiceImpl and AjaxServiceImpl
org.apache.jetspeed.layout.impl.*

This is still a work in progress..

In a custom project, we wrote an AJAX treeview widget with Rico. The 
code is mixed in another project but was more of a first time prototype, 
so its not integrated with the ongoing work in subversion head. It uses 
a concept of builders and actions to supply XML responses over HTTP. 
Here is an example builder that builds a tree view, the javascript to 
expand and contract, and finally the service that handles the request. 
Since doing this work, Ive been working on porting it back into 
Jetspeed, although I haven't considering porting back the treeview yet. 
The builder and action classes are not included here, since they are 
being refactored in the SVN trunk. It would be best if we ported the 
treeview code back to the new AJAX services and builders in SVN trunk. 
I'd be glad to work with you on that.

<?xml version="1.0"?>
#macro (ajaxChildren $children)
   #foreach( $child in $children)
     #set($isLeaf = "false")
     #set($isDocument = "false")
     #if($child.isLeaf() == true)
     	#set($isLeaf = "true")
     #end
     #if($child.isDocument() == true)
     	#set($isDocument = "true")
     #end
   	<child label="$child.label" name="$child.name" isLeaf="$isLeaf" 
isDocument="$isDocument" #if($child.anchor.length() > 0) 
anchor="$child.anchor" #end >
         #if($child.getChildren().size() > 0)
             #set($grandchildren = $child.getChildren())
             #ajaxChildren($grandchildren)
         #end
     </child>
   #end
#end
<ajax-response>
<response type="object" id="treeUpdater"><node name="${ajaxnode.name}" 
contextPath="$contextPath">
   #set($t = $ajaxnode.getChildren())
   #ajaxChildren( $t )
</node>
</response>
</ajax-response>

Javascript to expand / contract tree nodes:

var treeBuilder = "";
var documentBuilder = "";
var loaded = { };
var currentDocument = "";
var expandTree = "";

var TreeUpdater = Class.create();
/*
TreeUpdater.attributes = [ "fullName", "title", "firstName", "lastName", 
"streetAddress",
"city", "state", "zipcode", "occupation", "phoneNumber", "mobileNumber", 
"personNotes"  ];*/

TreeUpdater.prototype = {

    initialize: function() {
       this.useHighlighting    = true;
       this.lastNodeSelected = null;
    },

    ajaxUpdate: function(ajaxResponse) {
    	log("Received response from server");
	this.updateTree(ajaxResponse.childNodes[0]);
	},
	updateTree: function(node) {
		this.lastNodeSelected = node;
		
		log("Found node with nodeName=" + node.nodeName);
		var treeNodeName = node.getAttribute("name");
		log("TreeNodeName=" + treeNodeName);
		var div = document.getElementById(treeNodeName);
		div.style.display = "inline";
		log("DIV Object Id =" + div);
		
		this.updateExpandInfo(treeNodeName);

		var html = this.outputChildren(node, treeNodeName);

		div.innerHTML = html;
         html = null;
	},
     updateExpandInfo: function(treeNodeName) {
         //var a = document.getElementById("PLUS_" + treeNodeName);
		//a.innerHTML = "-";
     },
     outputChildren: function(node, treeNodeName) {
         var children = node.childNodes;
         var html = "";//"<ul>"
		log("Number of Children = " + children.length);
		
		for(var i=0; i< children.length; ++i) {
             var child = children[i];
	        log("Found child " + child.nodeName);
	        if(child.nodeName == "#text") continue;

             var childName = child.getAttribute("name");
             var label = child.getAttribute("label");
             var title = child.getAttribute("title");

             var hasChildren = 
child.getElementsByTagName("child").length > 0;

             //loaded[childName] = "false";

             log("ChildNodeName=" + child.nodeName);
             log("childName=" + childName);
             var isLeaf = child.getAttribute("isLeaf");
             html = html + "<li>";

             /*
             if(isLeaf == "true") {
               //do nothing
             } else {
               html = html + "<a id=\"PLUS_" + childName + "\" ";
               if(title != null) { html = html + "title=\"" + title + 
"\" "; }
               html = html + "href=\"javascript:getNodeInfo('" + 
childName + "');\"> "
               if(hasChildren) {
                   html = html + "-";
               } else {
                   html = html + "+";
               }
               html = html + " </a>";
             }
             */

             var spanStyle = "<span>";
             var isDoc = child.getAttribute("isDocument");
             var anchor = child.getAttribute("anchor");
             if(isDoc == "true") {
                 html = html + "<a href=\"javascript:getDocInfo('" + 
childName +"');\">" + spanStyle + label + "</span></a>";
             } else if(anchor != null && currentDocument == treeNodeName) {
                 html = html + "<a href=\"" + anchor + "\">" + label + 
"</a>";
             } else if(anchor != null) {
                 log("Anchor=" + anchor);
                 html = html + "<a href=\"javascript: currentAnchor='" + 
anchor + "'; getDocInfo('" + childName +"');\">" + spanStyle + label + 
"</span></a>";
             } else {
                 html = html + spanStyle + "&nbsp; <a 
href=\"javascript:getNodeInfo('" + childName + "');\"> " + label + 
"</a></span>";
             }
             html = html + "<div id=\"" + childName + "\" ";

             if(hasChildren) {
                 html = html + "style=\"display:inline;\"";
             } else {
                 html = html + "style=\"display:none;\"";
             }
             html = html + ">";

             if(child.childNodes.length > 0) {
                 html = html + this.outputChildren(child, treeNodeName);
             }
             html = html + "</div>";
             html = html + "</li>";
		}

         if(html.length > 0) {
             html = "<ul>" + html + "</ul>";
         } else {
             //html = "&nbsp;";
         }
         log(html);
         return html;
     }

		/*
	substitute: function( tagName, tagClass, value ) {
		var elements = document.getElementsByTagAndClassName(
		tagName, tagClass);
		for ( var i = 0 ; i < elements.length ; i++ )
		elements[i].innerHTML = value;
		},*/
};

function getDocInfo(nodeName) {
    	log("Sending doc info request");
	
	var now = new Date();
	log("Started at " + formatTime(now));
	
     log("NodeName=" + nodeName);
     log("CurDoc=" + currentDocument);

     if(nodeName && nodeName.length > 0) {
         var hash = nodeName.indexOf("#");
         var anchor = "";
         if(hash != -1) {
             anchor = nodeName.substring(hash);
             nodeName = nodeName.substring(0, hash);
         }
     }

     if(currentDocument && currentDocument.length > 0 && 
currentDocument.indexOf(nodeName) >= 0) {
         log(anchor);
         if(anchor.length > 0) {
             location.hash = anchor;
         }
         log("Returning..."); return;
     }
     currentDocument = nodeName;

     if(nodeName == null) {
         nodeName = "";
     }

     var ranNum= Math.random()*4;
    	ajaxEngine.sendRequest( 'getDocInfo', "node=" + nodeName, 
"builder=" + documentBuilder, "random="+ranNum);
   }

   function expand(nodeName) {
       log("Sending expand info");
       var ranNum= Math.random()*4;
       ajaxEngine.sendRequest( 'expandState', "node=" + nodeName, 
"action=expandState", "expandTree="+expandTree, "random="+ranNum);
   }

    function getNodeInfo(nodeName) {
       var div = document.getElementById(nodeName);
       //var a = document.getElementById("PLUS_" + nodeName);
       log(nodeName);

       if(loaded[nodeName] == "true") {
         log("Request div info for already loaded div.  Will hide or 
display as appropriate.");
       	if(div.style.display == "none") {
		    log("Displaying node " + nodeName);
             div.style.display = "inline";
             //a.innerHTML = "-";
             expand(nodeName);
         } else {
		    log("Hiding node " + nodeName);
             div.style.display = "none";
             //a.innerHTML = "+";
             expand(nodeName);
         }
       } else {
           if(div.style.display == "none") {
              log("Sending AJAX request to server");
              ajaxEngine.sendRequest( 'getNodeInfo', "node=" + nodeName, 
"builder=" + treeBuilder);
              expand(nodeName);
           }
	      loaded[nodeName] = "true";
           //expand(nodeName); //TODO: add action param to getNodeInfo 
request, combine http request this way
       }
     }

     function expandRoot() {
         log("expandRoot");
         var ranNum= Math.random()*4;
         ajaxEngine.sendRequest( 'getNodeInfo', "node=ROOT-NODE", 
"builder="+treeBuilder, "random="+ranNum);
     }

THe Java service:

package com.xxxxx.xxxx.services.ajax;

import java.io.*;
import java.util.Map;

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

import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.context.Context;

import xxx.xxxxx.xxx.cms.request.XXXXRequestContext;
import xxx.xxxxx.xxx.cms.request.XXXXRequestContextImpl;
import xxx.xxxxx.xxx.services.context.builder.ContextBuilder;
import xxx.xxxxx.xxx.services.context.velocity.VelocityContextImpl;

/**
  * @author Jeremy Ford
  *
  */
public class AjaxService
{
     private boolean debug = false;

     private static final String WAIT_FOR_RESPONSE = "WAIT_FOR_RESPONSE";
     private static final String CONTENT_TYPE = "text/xml";
     private static final String AJAX_PROCESSOR = "AJAX processor";

     private static final String BUILDER = "builder";
     private static final String ACTION = "action";

     private VelocityEngine engine = null;
     private Map builders;
     private Map actions;

     private String velocityProperties = 
"/WEB-INF/velocity/velocity.properties";

     public AjaxService(Map builders)
     {
         this.builders = builders;
     }

     public AjaxService(Map builders, Map actions, VelocityEngine engine)
     {
         this.builders = builders;
         this.actions = actions;
         this.engine = engine;
     }

     public ContextBuilder getBuilder(String key)
     {
         return (ContextBuilder) builders.get(key);
     }

     public void init(ServletConfig config) throws Exception
     {
         /*
         if (engine == null)
         {
             engine = new VelocityEngine();
             Properties props = new Properties();

             props.load(config.getServletContext().getResourceAsStream(
                     velocityProperties));
             engine.init();
         }
         */
     }

     public void process(HttpServletRequest request,
             HttpServletResponse response, ServletConfig servletConfig)
     {
         processAction(request, response, servletConfig);
         processRequest(request, response, servletConfig);
     }

     public void processAction(HttpServletRequest request,
             HttpServletResponse response, ServletConfig servletConfig)
     {
         XXXXRequestContext requestContext = new 
XXXXRequestContextImpl(request,
                 response, servletConfig);

         String actionKey = request.getParameter(ACTION);
         if(actionKey != null) {
             AJAXRunnable action = (AJAXRunnable) actions.get(actionKey);

             String waitForResponse = 
request.getParameter(WAIT_FOR_RESPONSE);

             boolean wait = true; //by default, wait for response

             if(waitForResponse != null) {
                 Boolean.getBoolean(waitForResponse);
             }
             if(wait) {
                 action.run(requestContext);
             } else {
                 //TODO:  handle pooling
                 Thread t = new Thread(action);
                 t.start();
             }
         }
     }

     public void processRequest(HttpServletRequest request,
             HttpServletResponse response, ServletConfig servletConfig)
     {
         response.setContentType(CONTENT_TYPE);

         XXXXRequestContext requestContext = new 
XXXXRequestContextImpl(request,
                 response, servletConfig);

         Context context = new VelocityContext();
         VelocityContextImpl responseContext = new 
VelocityContextImpl(context);

         String builderKey = request.getParameter(BUILDER);
         ServletContext servletContext = request.getSession()
                 .getServletContext();

         ContextBuilder builder = getBuilder(builderKey);
         if (builder == null)
         {
             buildError();
         }
         else
         {
             try
             {
                 StringWriter writer = new StringWriter();
                 boolean result = builder.buildContext(requestContext,
                         responseContext);
                 if (result)
                 {
                     final InputStream templateResource = servletContext
                             .getResourceAsStream(builder.getTemplate());
                     Reader template = new 
InputStreamReader(templateResource);
                     engine.evaluate(context, writer, AJAX_PROCESSOR, 
template);

                     String buffer = writer.getBuffer().toString();
                     if (debug)
                     {
                         System.out.println(buffer);
                     }
                     response.getWriter().write(buffer);
                 }
                 else
                 {
                     buildError();
                 }
             }
             catch (Exception e)
             {
                 //TODO: log
                 buildError();
                 e.printStackTrace();
             }
         }
     }

     private void buildError()
     {

     }
     /**
      * @param velocityProperties The velocityProperties to set.
      */
     public void setVelocityProperties(String velocityProperties)
     {
         this.velocityProperties = velocityProperties;
     }
}

---------------------------------------------------------------------
To unsubscribe, e-mail: jetspeed-dev-unsubscribe@portals.apache.org
For additional commands, e-mail: jetspeed-dev-help@portals.apache.org


Mime
View raw message