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: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to