You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jetspeed-dev@portals.apache.org by Christophe Lombart <ch...@gmail.com> on 2005/11/24 11:29:01 UTC

Ajax

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.

Thanks,
Christophe

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


jetspeed.properties

Posted by David Sean Taylor <da...@bluesunrise.com>.
In the goal j2:portal.copy.webapp.minimal, we exclude jetspeed.properties:

         <exclude name="WEB-INF/conf/jetspeed.properties"/>

why is that?

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


Re: Ajax

Posted by David Sean Taylor <da...@bluesunrise.com>.
Christophe Lombart wrote:
> On 11/28/05, David Sean Taylor <da...@bluesunrise.com> wrote:
> 
>>Here we configure the security constraint or RBAC
>>I think I may simply go with RBAC for now
>>Let me know what you think, I should be able to get this into the Ajax
>>Pipeline today
>>
> 
> 
> RBAC is also ok for me. In your example,  what kind of component is
> AjaxGetRoles ? is it a simple portal service ?
> 
No, although arguably it could be.
Instead we have Ajax Actions and Builders:

public class AddGetRoles
     implements AjaxAction, AjaxBuilder

working very much like a portlet, in that its two-phase.
First phase is the action, second phase is the builder, building the 
Ajax XML response.

> 
> I like the solution #1 but I expect to write more javascript no ?
> Solution #2 avoid to write a lot of java script. A simple ajax respond
> with Rico can be (to update a group listbox) :
> 
> <ajax-response>
> 	<response type="element" id="group">	 		  					
> 		    <option value="g1">
> 					Group1
> 		    </option>
> 		    <option value="g2">
> 					Group2
> 		    </option>			
> 	</response>
> 	
> </ajax-response>
> 
> But I'm ok the solution #1 is better in point of view design. Do you
> make a choice for an ajax framework ?
>
I think you can use either way with this Ajax framework.
As long as there is some way to know the content type of the response


-- 
David Sean Taylor
Bluesunrise Software
david@bluesunrise.com
[office] +01 707 773-4646
[mobile] +01 707 529 9194

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


Re: Ajax

Posted by Christophe Lombart <ch...@gmail.com>.
On 11/28/05, David Sean Taylor <da...@bluesunrise.com> wrote:
> Here we configure the security constraint or RBAC
> I think I may simply go with RBAC for now
> Let me know what you think, I should be able to get this into the Ajax
> Pipeline today
>

RBAC is also ok for me. In your example,  what kind of component is
AjaxGetRoles ? is it a simple portal service ?

> > I'm making a prototype in Graffito with Rico and the ajax services.
> > I'm wondering what is the best approach to return the desired
> > information to update in my browser. I see 2 possibilities :
> > 1. Use an xml file like  portlet_apps.ajax which required more javascripts.
> > 2. Use an xml containing the html element reference to update (method
> > suggested by Rico).
> >
> > When using Rico or such ajax framework, is it make sense to use the
> > second solution ?
> > If not, are there some javascript to update the html element with the
> > xml data ?
> >
>
> My approach has been #1, since XML gives us a clean separation between
> content and markup. Its then up to the script to format the result.
> Im not sure if I actually understand #2
>

I like the solution #1 but I expect to write more javascript no ?
Solution #2 avoid to write a lot of java script. A simple ajax respond
with Rico can be (to update a group listbox) :

<ajax-response>
	<response type="element" id="group">	 		  					
		    <option value="g1">
					Group1
		    </option>
		    <option value="g2">
					Group2
		    </option>			
	</response>
	
</ajax-response>

But I'm ok the solution #1 is better in point of view design. Do you
make a choice for an ajax framework ?

Thanks,
Christophe

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


Re: Ajax

Posted by David Sean Taylor <da...@bluesunrise.com>.
Christophe Lombart wrote:
> David,
> 
> If I understand correctly, The ajax service gives the possibility to
> call some portal services from ajax client. What about the security ?
> Eg. I would like to get groups, users and roles to populate tree view
> or list boxs. How to secure this kind of call ?
>
What about in the action definition in the spring configuration:

<bean id="AjaxGetRoles"
...

     <!-- Security Constraint Ref OR role-based-access-constraints -->
     <constructor-arg index='3'>
         <value>requires-admin</value>
--OR--
         <value>admin</value>
     </constructor-arg>

</bean>

Here we configure the security constraint or RBAC
I think I may simply go with RBAC for now
Let me know what you think, I should be able to get this into the Ajax 
Pipeline today

> I'm making a prototype in Graffito with Rico and the ajax services.
> I'm wondering what is the best approach to return the desired
> information to update in my browser. I see 2 possibilities :
> 1. Use an xml file like  portlet_apps.ajax which required more javascripts.
> 2. Use an xml containing the html element reference to update (method
> suggested by Rico).
> 
> When using Rico or such ajax framework, is it make sense to use the
> second solution ?
> If not, are there some javascript to update the html element with the
> xml data ?
>

My approach has been #1, since XML gives us a clean separation between 
content and markup. Its then up to the script to format the result.
Im not sure if I actually understand #2


> 
> Last question : is it possible to call some portlet actions with ajax
> ? is it make sense to doing that ?

Sure, it is possible. You can create action URLs in your page, and then 
have Ajax call that URL. We have not used this approach, instead 
handling the requests in the pipeline, allthough I think its a valid 
approach, it ties the Ajax calls to a particular portlet entity on a page

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


Re: Ajax

Posted by Christophe Lombart <ch...@gmail.com>.
David,

If I understand correctly, The ajax service gives the possibility to
call some portal services from ajax client. What about the security ?
Eg. I would like to get groups, users and roles to populate tree view
or list boxs. How to secure this kind of call ?

I'm making a prototype in Graffito with Rico and the ajax services.
I'm wondering what is the best approach to return the desired
information to update in my browser. I see 2 possibilities :
1. Use an xml file like  portlet_apps.ajax which required more javascripts.
2. Use an xml containing the html element reference to update (method
suggested by Rico).

When using Rico or such ajax framework, is it make sense to use the
second solution ?
If not, are there some javascript to update the html element with the
xml data ?


Last question : is it possible to call some portlet actions with ajax
? is it make sense to doing that ?

Kind regards,
Christophe





On 11/24/05, David Sean Taylor <da...@bluesunrise.com> wrote:
> Christophe Lombart wrote:
> > David,
> >
> > I'm going to review the code. Do you advise me to review Rico ?
>
> Well, maybe. Im reviewing both Rico and http://script.aculo.us/
>
> I can send you a zip of the files, although I first need to strip out
> the proprietary stuff....
>
>
> > Do you
> > plan to integrate it into Jetspeed ?
> >
> Yes, of course. We hope to have this all in over the next week
>
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: jetspeed-dev-unsubscribe@portals.apache.org
> For additional commands, e-mail: jetspeed-dev-help@portals.apache.org
>
>

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


Re: Ajax

Posted by David Sean Taylor <da...@bluesunrise.com>.
Christophe Lombart wrote:
> David,
> 
> I'm going to review the code. Do you advise me to review Rico ? 

Well, maybe. Im reviewing both Rico and http://script.aculo.us/

I can send you a zip of the files, although I first need to strip out 
the proprietary stuff....


> Do you
> plan to integrate it into Jetspeed ?
>
Yes, of course. We hope to have this all in over the next week




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


Re: Ajax

Posted by Christophe Lombart <ch...@gmail.com>.
David,

I'm going to review the code. Do you advise me to review Rico ? Do you
plan to integrate it into Jetspeed ?

Thanks,
Christophe

On 11/24/05, David Sean Taylor <da...@bluesunrise.com> wrote:
> 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
>
>

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


Re: Ajax

Posted by David Sean Taylor <da...@bluesunrise.com>.
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