Arch2Arch Tab BEA.com
Syndicate this blog (XML)

Mashing Up wlp.bea.com using REST

Bookmark Blog Post

del.icio.us del.icio.us
Digg Digg
DZone DZone
Furl Furl
Reddit Reddit

Skip Sauls' Blog | July 6, 2007   2:41 PM | Comments (0)


In my previous blog entry I introduce the prototype REST commands that we have made available on wlp.bea.com. There are commands for accessing content, user profiles, and various portal assets, all of which can now be used outside of WebLogic Portal. In this entry I'll discuss some of the ways to use these commands with a simple JavaScript client.

Mashups by Proxy

If you've ever tried using an XMLHttpRequest you may have run into the cross-site scripting (XSS) issue. This security feature of web browsers can make mashups a bit difficult as it prevents the use of anything outside of the original domain. There are a few different ways around this, including Greasemonkey, which is discussed by Peter Laird in some of his recent blogs. Peter has been covering a variety of technologies for mashups, Web 2.0, etc, and are a worthwhile read.

I've been using a proxy servlet based on the one that John Margaglione posted in his article Ajax Programming in BEA WebLogic Portal 8.1, Part 2. My modifications are mainly to set the HTTP request method and do some basic authorization to the proxied site. It should be noted that I'm not suggesting that this proxy is secure, so be careful. It will work fine for prototypes, demos, and for learning, but it's not meant for production use.

package test.proxy;

import java.io.*;
import java.net.*;
import java.util.*;

import javax.security.auth.login.LoginException;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import javax.servlet.ServletOutputStream;

import com.bea.p13n.security.Authentication;

public class ProxyServlet extends javax.servlet.http.HttpServlet 
{
	private static final long serialVersionUID = 0L;
	
	protected void service(HttpServletRequest request, HttpServletResponse response, String method)  throws ServletException, IOException
	{
		// The base 64 encoded username:password parameter
		String userPassword = request.getParameter("_up");
		
		String surl = URLDecoder.decode(request.getParameter("url"), "UTF-8");

		Map paramMap = request.getParameterMap();
        Iterator keys = paramMap.keySet().iterator();
        
        boolean first = true;

        if (request.getParameterMap().size() > 1) 
        {
        	if (surl.contains("?"))
        		surl += "&";
        	else
        		surl += "?";
        }

        while (keys.hasNext())
        {
        	String name = (String) keys.next();
        	if (!name.equals("url") && !name.equals("_up"))
        	{
        		if (!first)
                	surl += "&";
                surl += name + "=" + request.getParameter(name);
                first = false;
            }
        }

        URL url = new URL(surl);

        HttpURLConnection uc = (HttpURLConnection) url.openConnection();
        
        uc.setRequestMethod(method);

        if (userPassword != null && !"".equals(userPassword))
        	uc.setRequestProperty("Authorization", "Basic " + userPassword);

        InputStream is = uc.getInputStream();
        
        while(true)
        {
            byte[] bytes = new byte[128];
            int read = is.read(bytes);
            if (read <= 0)
            	break; 
            response.getOutputStream().write(bytes, 0, read);
        }
    }
    
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 
    {
        service(request, response, "GET");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 
    {
        service(request, response, "POST");
    }

    protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 
    {
        service(request, response, "PUT");
    }
    
    protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 
    {
        service(request, response, "DELETE");
    }
}

To use this servlet you'll need to provide a mapping in web.xml such as:

<servlet>
  <servlet-name>ProxyServlet</servlet-name>
  <servlet-class>test.proxy.ProxyServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>ProxyServlet</servlet-name>
  <url-pattern>/proxy</url-pattern>
</servlet-mapping>

Note that if you don't use the url-pattern /proxy you'll need to adjust the sample code accordingly. You should also be able to use any other proxy servlet, service, etc., along with tools such as Microsoft Popfly that do the proxying. One of the great things about many of the Web 2.0 concepts is that they are largely language and product independent, freeing the client from the server.

The Simplest Client

If you've read the previous article and tried out some of the sample URLs, you've scratched the surface a bit. Doing things with just URLs in a browser is cumbersome, and you can't really much more than get the results. To make things more interesting we'll need a bit of client side code, with the following as perhaps the simplest example:

<html>
<head><title>Tiny REST</title></head>
<body>
<form action="">
  <input type="text" name="path" size="50" value=""/>
  <input type="button" onclick="show(this.form.path.value)" value="Show Image"/>
</form>
<img src="" id="image"/>
<script type="text/javascript">
function show(path) {
	var xmlHttpReq = false;
	if (window.ActiveXObject) { // IE
		xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
	} else if (window.XMLHttpRequest) {  // Mozilla/Safari
		xmlHttpReq = new XMLHttpRequest();
		xmlHttpReq.overrideMimeType('text/html');
	}
	var proxyUrl = "http://localhost:7001/portalTools/proxy?url=";
	var url = "http://wlp.bea.com/rest-web-lib/api/content.node"
	url += "?format=json&nodePath=" + path;
	url = proxyUrl + url;
	xmlHttpReq.open("GET", url, true);
	xmlHttpReq.setRequestHeader("Content-Type", "text/html");
	xmlHttpReq.onreadystatechange = function() {
		if (xmlHttpReq.readyState == 4) {
    		var result = eval('(' + xmlHttpReq.responseText + ')');
			var properties = result.content.properties;
			var img = document.getElementById("image");
			for (i in properties)
				if (properties[i].name == "file")
					for(j in properties[i].values)
						if (properties[i].values[j].contentType.match("image"))
							img.src = "http://wlp.bea.com" + properties[i].values[j].value;
		}
	}
	xmlHttpReq.send(null);
}
</script>
</body>
</html>

To use this example you'll need to host it on the same server as the proxy, and you may need to modify the proxyUrl value accordingly. If you've been using WebLogic products then you'll probably recognize the value used in the sample above. You can put the sample HTML pretty much anywhere on the same server, and it will work fine as a JSP, etc.

When you access this from a web browser you'll see the following:

Try entering the path /BEA Repository/Demo/Logos/BEA into the field and press the button to see the following:

There are some other images in this folder, including AlfredChuang, BernersLee, and BEA Boulder. You can also find several images under the /BEA Boulder/Smithsonian folder, including plane1, Concorde1, and SR71, a plane that BEA's Ron Schweikert has some experience with.

So how can we display a list of links to make these folders browseable? There is a content node list REST command available, as you may recall from the previous entry. Using this we can get back the name, type, node path, and more for all of the nodes within a folder. The parameters that this command needs are the repositoryName and nodePath. The public repository on wlp.bea.com is called the BEA Repository, which is no surprise.

At the top level of this repository are several folders, some of which have subfolders, along with content of various types. The two types that we'll concern ourselves with now are article and image, which have several properties. When we retrieve a node we can use these properties to display the images, titles, etc. if desired. The code below is a modified version of the sample above, with additions for browsing the folder hierarchy and viewing images or articles. It's content browser in less than 100 lines, and it could probably be even shorter.

<html>
<head><title>Tiny REST 2</title></head>
<body onload="listNodes(document.forms.inputForm.path.value);">
<form name="inputForm" action="">
  <input type="text" name="path" id="path" size="50" value=""/>
  <input type="button" onclick="listNodes(this.form.path.value)" value="List Nodes"/>
</form>
<div id="nodeList" style="height: 200px; overflow: auto; border: 1px solid #C0C0C0;">
</div>
<div id="outputDiv" style="height: 200px; overflow: auto; border: 1px solid #C0C0C0;">
</div>
<script type="text/javascript">
function show(path) {
	var xmlHttpReq = false;
	if (window.ActiveXObject) { // IE
		xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
	} else if (window.XMLHttpRequest) {  // Mozilla/Safari
		xmlHttpReq = new XMLHttpRequest();
		xmlHttpReq.overrideMimeType('text/html');
	}
	var proxyUrl = "http://localhost:7001/portalTools/proxy?url=";
	var url = "http://wlp.bea.com/rest-web-lib/api/content.node"
	url += "?format=json&nodePath=" + path;
	url = proxyUrl + url;
	xmlHttpReq.open("GET", url, true);
	xmlHttpReq.setRequestHeader("Content-Type", "text/html");
	xmlHttpReq.onreadystatechange = function() {
		if (xmlHttpReq.readyState == 4) {
    		var result = eval('(' + xmlHttpReq.responseText + ')');
			var properties = result.content.properties;
			var img = document.getElementById("image");
			var outputDiv = document.getElementById("outputDiv");
			outputDiv.innerHTML = "";
			for (i in properties)
				if (properties[i].name == "file")
					for(j in properties[i].values)
						if (properties[i].values[j].contentType.match("image")) {
							var img = document.createElement("img");
							img.src = "http://wlp.bea.com" + properties[i].values[j].value;
							outputDiv.appendChild(img);
						} else if (properties[i].values[j].contentType.match("text"))
							outputDiv.innerHTML = properties[i].values[j].value;
		}
	}
	xmlHttpReq.send(null);
}

function listNodes(path) {
	var xmlHttpReq = false;
	if (window.ActiveXObject) { // IE
		xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
	} else if (window.XMLHttpRequest) {  // Mozilla/Safari
		xmlHttpReq = new XMLHttpRequest();
		xmlHttpReq.overrideMimeType('text/html');
	}
	var proxyUrl = "http://localhost:7001/portalTools/proxy?url=";
	var url = "http://wlp.bea.com/rest-web-lib/api/content.nodelist"
	url += "?format=json&nodePath=" + path;
	url += "&repositoryName=BEA Repository";
	url = proxyUrl + url;
	xmlHttpReq.open("GET", url, true);
	xmlHttpReq.setRequestHeader("Content-Type", "text/html");
	xmlHttpReq.onreadystatechange = function() {
		if (xmlHttpReq.readyState == 4) {
    		var result = eval('(' + xmlHttpReq.responseText + ')');
    		var nodes = result.content.nodes;
    		var pathDiv = document.getElementById("path");
    		var nodeListDiv = document.getElementById("nodeList");
    		nodeListDiv.innerHTML = "";
   			var linkDiv = document.createElement("div");
    		linkDiv.innerHTML = "Parent Folder";
    		linkDiv.name = result.content.nodePath.substring(16);
    		pathDiv.value = linkDiv.name;
    		linkDiv.name = linkDiv.name.substring(0, linkDiv.name.lastIndexOf("/"));
    		linkDiv.onmousedown = function(evt) { listNodes(evt.target.name); };
    		nodeListDiv.appendChild(linkDiv);
    		for (i in nodes) {
    			linkDiv = document.createElement("div");
    			linkDiv.style.color = "blue";
    			linkDiv.innerHTML = nodes[i].name;
    			if (nodes[i].type == "folder") {
    				linkDiv.name = nodes[i].path.substring(16); // Strip /BEA Repository/
    				linkDiv.onmousedown = function(evt) { listNodes(evt.target.name); };
    			} else if (nodes[i].type == "image" || nodes[i].type == "article") {
    				linkDiv.name = nodes[i].path;
    				linkDiv.onmousedown = function(evt) { show(evt.target.name); };
    			}
    			nodeListDiv.appendChild(linkDiv);
    		}
		}
	}
	xmlHttpReq.send(null);
}
</script>
</body>
</html>

Save this to a file on the server and open it in a browser to see a display such as:

Parent Folder
Demo
Financials
Improv
Smithsonian
spreadsheets
swivelgraphs

Click on Demo then Images and finally Logos to see the list of images we used above. Click on BEA to open the BEA logo as follows:

Parent Folder
BernersLee
BEA
BEA Boulder
AlfredChuang

You can click on the Parent Folder link to go up a level, and if you go to Demo/Articles you can click on Lorem Ipsum to see the following:

Parent Folder
Web 2.0 Definition
History of Web 2.0
Ajax and WLP 10 FAQ
Lorem Ipsum
AquaLogic Commerce Services Released
Adrenalize Vista
Using the Blog Portlet

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas ut ligula. Maecenas eleifend ligula sit amet purus. Curabitur nonummy justo in elit. Maecenas leo risus, volutpat eget, sodales non, euismod sed, lorem. Nam faucibus leo ut risus. Morbi eget enim faucibus turpis feugiat porttitor. Sed sodales facilisis tellus. Phasellus facilisis felis id felis. Cras volutpat neque vel neque. Nulla libero nisl, vehicula vel, iaculis id, sagittis id, ante. Duis eu purus. Phasellus blandit arcu a diam adipiscing ullamcorper. Aliquam facilisis, sapien ut blandit luctus, diam leo aliquet risus, nec consequat elit dui non turpis. Quisque blandit. Donec tellus. Nam quis sem nec dui egestas consectetuer. Donec volutpat, orci id feugiat pharetra, libero ante malesuada sapien, eget venenatis orci dolor in sapien.

Integer interdum adipiscing lorem. Etiam dictum tincidunt dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Fusce ornare sem non leo. Maecenas viverra. Fusce id metus. Donec imperdiet enim sit amet enim. Nulla vitae nisi quis ipsum varius tempus. Phasellus eros. Curabitur fermentum dui quis pede. Nam iaculis fermentum mauris.

Cras molestie lobortis nulla. Morbi eu diam. Nullam molestie tempus elit. Cras pharetra, libero vitae posuere gravida, elit risus convallis risus, at semper orci velit in est. Vestibulum egestas tempor lorem. Praesent ornare tempus lorem. Duis nec orci nec libero placerat eleifend. Sed malesuada felis non velit. In ac massa a lorem bibendum egestas. Aenean eleifend mattis lacus. In consectetuer libero quis tellus. Donec est. Sed elementum. Praesent faucibus mollis tellus. Fusce eget quam. Vestibulum id est. In elementum. Mauris tincidunt sagittis ante. Mauris felis risus, tristique quis, sollicitudin non, porta ut, enim. Nulla facilisi.

Nunc non nisi vitae eros nonummy elementum. Fusce nec lacus sit amet justo condimentum tincidunt. Maecenas ligula mi, placerat at, consectetuer sed, posuere at, arcu. Proin id urna. Praesent vitae velit a pede mattis ullamcorper. Fusce eleifend, sapien in congue dapibus, dolor purus vehicula turpis, non auctor lacus tortor at massa. Donec sem. In hac habitasse platea dictumst. Integer nunc. Donec convallis nisi et risus. Ut molestie elit non sapien. In urna. Praesent sodales urna vel odio. Sed sit amet ipsum et ipsum nonummy molestie. Donec vel ligula ut nulla lobortis convallis. Etiam adipiscing. Cras volutpat neque ut lorem. Nullam blandit nibh.

Nulla euismod. Morbi vestibulum tellus a sapien. Vivamus semper. Sed euismod scelerisque nulla. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. In eu justo a lectus vehicula facilisis. Sed nulla enim, sodales egestas, facilisis sed, cursus ac, nibh. Nunc tempor lectus a mauris. Curabitur iaculis felis quis diam. In euismod diam imperdiet dolor. Vivamus feugiat ullamcorper ipsum. Vestibulum ultrices. Curabitur arcu. Phasellus hendrerit orci non orci. Praesent accumsan. Nam eget velit. Suspendisse sodales mi in ipsum.

Making It All Easier

If you've been examining the code samples you'll recognize that they aren't at all modular or easily reusable. Hopefully they will show you how to use some of the REST commands, but I promise you it gets better and easer. In the next few blog entries I'll introduce some JavaScript functions that you can use, as well as some Dojo-based widget that make it even easier. The source code for all of these will be provided so you can adapt them as needed.

.

If you've been using Web 2.0 technologies and would like to see how they might be used with WebLogic Portal, I'd love to hear about them.


Comments

Comments are listed in date ascending order (oldest first) | Post Comment



Only logged in users may post comments. Login Here.

Powered by
Movable Type 3.31