Thursday, March 29, 2007

Credential renewal with MyProxy and JGlobus

I'm currently working on create a service as part of the LEAD project that will be responsible for kept grid credentials fresh for the duration of a workflow or some other user process. I've been experimenting with the capabilities of MyProxy and JGlobus to this end.

First of all, the MyProxy site has an excellent page on various grid credential renewal issues and MyProxy. So to begin, I want to set my credential renewer service as a "default renewer" in the MyProxy configuration. I do this by adding

default_renewers "DN of my renewing service"

to the myproxy-server.config file. Now my renewing service can renew credentials stored in this MyProxy server. Next, I store a proxy in MyProxy without a passphrase, so that MyProxy can use it for proxy renewal.

myproxy-init -n -s myproxy-server.mydomain.org -l myusername

The -n option says to store the proxy without a passphrase. Now I can renew this proxy with

myproxy-logon -s myproxy-server.mydomain.org -a /tmp/aging_proxy \
-l myusername -o /tmp/refreshed_proxy

In the previous command, -a specifies the proxy that we want to renew. For this to work, you either need to have loaded a proxy credential of the renewing service, or you need to set the X509_USER_CERT and X509_USER_KEY environment variables to the locations of the certificate and unencrypted key of your renewing service. And to do MyProxy renewal using the JGlobus API, it looks like this:

MyProxy myproxy = new MyProxy(myproxyHost, myproxyPort);
GetParams getParams = new GetParams();
getParams.setUserName(username);
getParams.setLifetime(24*60*60);
getParams.setAuthzCreds(userCred);

GSSCredential renewedCredential = myproxy.get(serviceCred, getParams);

Note that you need a valid MyProxy username as well as a still valid proxy credential. To load the service credential, do this:

GlobusCredential globusCred = new GlobusCredential(pathToServiceCert,
pathToServiceKey);
GSSCredential gssCred = new GlobusGSSCredentialImpl(globusCred,
GSSCredential.INITIATE_AND_ACCEPT);
An important thing to keep in mind (which I forgot halfway through this process) is that the credential stored in MyProxy cannot have a passphrase protecting it for it to be used to renew a proxy credential. We make use of the grid credential storage feature of MyProxy in the LEAD project, and for this to work with credential renewal, we first have to unencrypt the private key of the grid credential. Use openssl to do this:

openssl rsa -in ~/.globus/userkey.pem -out ~/.globus/userkey1.pem

Then store your credential to MyProxy with this key:

myproxy-store -s myproxy.mydomain.org -l myusername -y .globus/userkey1.pem

Now you'll be able to use this MyProxy credential for proxy renewal.

Wednesday, March 28, 2007

Setting the var attribute of dataTable in a facelet, part II

This time I take a completely different approach to this problem. The problem, by the way, is how to apply default Java Portlet API (JSR-168) CSS styles to the dataTable component. As shown in the previous post, this is complicated in Facelets by the fact that we can't just simply pass through a value for the var attribute of the dataTable component. But, this time that won't be an issue because we can simply extend the way Facelets handles the dataTable component and more directly apply the CSS styles we want.

After grepping through the Facelets source code, I discovered that HtmlComponentHandler is the TagHandler associated with the dataTable component (and all other HTML components as well). So I extended this with my own class, HtmlDataTableHandler:


package portletfacelets;

import javax.faces.component.UIComponent;
import javax.faces.component.html.HtmlDataTable;

import com.sun.facelets.FaceletContext;
import com.sun.facelets.tag.jsf.ComponentConfig;
import com.sun.facelets.tag.jsf.html.HtmlComponentHandler;

public class HtmlDataTableHandler extends HtmlComponentHandler {

public HtmlDataTableHandler(ComponentConfig config) {
super(config);
}

@Override
protected void onComponentCreated(FaceletContext ctx,
UIComponent c, UIComponent parent) {
super.onComponentCreated(ctx, c, parent);
if (c instanceof HtmlDataTable) {
HtmlDataTable table = (HtmlDataTable) c;
if (table.getFooterClass() == null) {
table.setFooterClass("portlet-section-footer");
}
if (table.getHeaderClass() == null) {
table.setHeaderClass("portlet-section-header");
}
if (table.getRowClasses() == null) {
table.setRowClasses("portlet-section-body," +
"portlet-section-alternate");
}
if (table.getStyleClass() == null) {
table.setStyleClass("portlet-section-body");
}
}
}

}


I check if the classes are null, to allow the user of the TagHandler to override the styles, but that's about it. The facelets taglib entry looks like this:


<tag>
<tag-name>dataTable2</tag-name>
<component>
<component-type>javax.faces.HtmlDataTable</component-type>
<renderer-type>javax.faces.Table</renderer-type>
<handler-class>portletfacelets.HtmlDataTableHandler</handler-class>
</component>
</tag>


I'm not sure which method I prefer, but I'm leaning toward the former, since it seems simpler and I like the idea of keeping things like CSS styles in a template file than in Java code, but in some sense this second approach also seems to be the cleaner one.

Running Portlets on Pluto from within Eclipse

The Pluto team recently released version 1.1.0 and as part of that release they include a very useful Pluto + Tomcat bundle that makes it very easy to get started. So I've been playing around with this and trying to figure out how to get it to work with Eclipse + WTP, and initially I ran into some issues. By default, WTP wants to take your application server and copy its files to a temporary location in which to deploy your webapp. However, this is fairly disastrous for portlet development because WTP doesn't copy everything and leaves behind important stuff like shared/lib, the portal webapp, etc. So I was trying to figure out what was left behind and manually copying the missing bits into the temporary location... aargh! And then I discovered a nice little feature of WTP. There is this "Run modules directly from the workspace" checkbox in the server settings for your app server, and unchecking this has the effect that Eclipse will deploy your web applications to the location of your app server and not some temporary location! So anyways, here are my notes on how to get this to work.

First, you need to register the Pluto 1.1/Tomcat 5.5.20 bundle with Eclipse as a Tomcat 5.5 server. Select File > New > Other and select Server, then click Next (or, if in the J2EE perspective, right click in the Servers View and select New > Server). Select a server type of "Tomcat v5.5", and click Next. Name it whatever you like, I call mine "Apache Tomcat v5.5 - Pluto". For "Tomcat installation directory:" browse to the location of where you installed the pluto bundle.




Click Finish. Now, we need to modify our Server definition for pluto just a bit, so go to the Servers view (if you don't have it, just switch to the J2EE perspective, or add the view with Window > Show View > Other..., then select Servers). Double click on your Pluto server defined there. Uncheck the "Run modules directly from the workspace" checkbox. We want Eclipse to run Pluto from the location of the pluto-bundle, so that it picks up the pluto webapp, shared/lib, and other bits that are needed because we are working with portlets.




Now, in order to run your portlet in Pluto from within Eclipse using WTP, you need to have your web.xml "pluto-ified". The Pluto guys have an Ant task called "assemble" which can do this for you, that's what I use. Just have it update your web.xml file (probably want to make a backup first). I've been working with a hello-world JSF Facelets sample portlet recently, here's how I get it running in Pluto:

Now we just need to get our application running on Pluto/Tomcat as before (right click on the Project, select Run As > Run on Server). The difference this time is that we will access our application through Pluto. In your web browser, go to http://localhost:8080/pluto. Login as user pluto, password pluto. In the upper left hand corner there is a label called "Navigation:". Mouse over this label to get a popup menu. Then select Pluto Admin from this list. Under Pluto Pages, select Pluto Admin from the drop down list. Then under Portlet Applications, select hello-world-jsf-facelets in the first drop down, and then in the second drop down select HelloWorldSamplePortlet, and click Add Portlet.



Now, the portlet should be there at the bottom of the page.



Note that the portlet pages configuration doesn't persist across restarts of the Pluto server. Consult the Pluto documentation if you want to persist the portal pages layout and configuration.

Now that our portlet is deployed to Pluto from within Eclipse, we can develop our portlet and have the changes immediately reflected in Pluto!

Thursday, March 22, 2007

Setting the var attribute of dataTable in a facelet

I'm currently working on a small little facelets suite to aid in portlet development. Initially, the idea is just to focus on making correct use of the portlet CSS styles implicit. So, for example, the following is the kind of code needed to set the portlet tables styles for the h:dataTable JSF component:


<h:dataTable value="#{mybean.myData}" var="row"
styleClass="portlet-section-body"
rowClasses="portlet-section-body,portlet-section-alternate"
headerClass="portlet-section-header">


So, I'd like to replace that with a facelet instead, so that it looks like this:


<p:dataTable value="#{mybean.myData}" var="row">


And the facelet would be defined once in a .xhtml file as:


<ui:composition>
<h:dataTable value="#{value}" var="#{var}"
styleClass="portlet-section-body"
rowClasses="portlet-section-body,portlet-section-alternate"
headerClass="portlet-section-header">
<ui:insert />
</h:dataTable>
</ui:composition>


However, this doesn't quite work. The problem is that it tries to set the var attribute of the dataTable component to a value expression, but dataTable requires a simple string for var. So we have to figure out some way of getting the var variable from the facelet into the dataTable component. What I came up with was a custom TagHandler that evaluates the value expression and then sets the var property of the dataTable component directly:


package portletfacelets;

import java.io.IOException;

import javax.el.ELException;
import javax.faces.FacesException;
import javax.faces.component.UIComponent;
import javax.faces.component.html.HtmlDataTable;

import com.sun.facelets.FaceletContext;
import com.sun.facelets.FaceletException;
import com.sun.facelets.tag.TagAttribute;
import com.sun.facelets.tag.TagConfig;
import com.sun.facelets.tag.TagHandler;

public class SetVarHandler extends TagHandler {

private final TagAttribute var;

public SetVarHandler(TagConfig config) {
super(config);
this.var = this.getAttribute("var");
}
public void apply(FaceletContext ctx, UIComponent parent)
throws IOException, FacesException, FaceletException, ELException {

System.out.println("var=" + this.var.getValue(ctx));

if (parent instanceof HtmlDataTable) {
HtmlDataTable table = (HtmlDataTable) parent;
table.setVar(this.var.getValue(ctx));
}


this.nextHandler.apply(ctx, parent);
}

}


I add this to my facelets taglib.xml file as such:


<tag>
<tag-name>setVar</tag-name>
<handler-class>portletfacelets.SetVarHandler</handler-class>
</tag>


And then use it like this in my facelet:


<ui:composition>
<h:dataTable value="#{value}"
styleClass="portlet-section-body"
rowClasses="portlet-section-body,portlet-section-alternate"
headerClass="portlet-section-header">
<p:setVar var="#{var}" />
<ui:insert />
</h:dataTable>
</ui:composition>


Voila! However, seeing as this might come in handy in future instances, I wondered if I couldn't make something a bit more generic. So I created this TagHandler:


package portletfacelets;

import java.io.IOException;
import java.lang.reflect.Method;

import javax.el.ELException;
import javax.faces.FacesException;
import javax.faces.component.UIComponent;

import com.sun.facelets.FaceletContext;
import com.sun.facelets.FaceletException;
import com.sun.facelets.tag.TagAttribute;
import com.sun.facelets.tag.TagConfig;
import com.sun.facelets.tag.TagHandler;

public class SetValueHandler extends TagHandler {

private final TagAttribute methodName;
private final TagAttribute value;

public SetValueHandler(TagConfig config) {
super(config);
this.methodName = this.getRequiredAttribute("methodName");
this.value = this.getRequiredAttribute("value");
}
public void apply(FaceletContext ctx, UIComponent parent)
throws IOException, FacesException, FaceletException, ELException {
try {

Method m = parent.getClass().getMethod(this.methodName.getValue(ctx),
new Class[]{String.class});
m.invoke(parent, new Object[]{this.value.getValue(ctx)});

} catch (Exception e) {
e.printStackTrace();
}

this.nextHandler.apply(ctx, parent);
}

}


So I'm using reflection to call any method on the parent JSF component and passing in the specified value. Then I use it in my facelet like so:


<ui:composition>
<h:dataTable value="#{value}"
styleClass="portlet-section-body"
rowClasses="portlet-section-body,portlet-section-alternate"
headerClass="portlet-section-header">
<p:setValue methodName="setVar" value="#{var}" />
<ui:insert />
</h:dataTable>
</ui:composition>


There you have it. Turns out there is more than one way to skin this cat, so I'll also share in a future blog post a different approach to this issue.

How to watch Google Videos on your DivX compatible DVD player

Google has put videos of their Tech Talks series online and I was interested in seeing if I could play these on my SD-3990 Toshiba DVD player which is DivX compatible. All you need to do is:
  1. Find the video at Google Video. Click the download link.
  2. The Google Video Player comes up and starts buffering the video. It saves the video into your My Videos/Google Video directory, or perhaps in a different location, you can check the preferences to see where the location is.
  3. The saved movie file has an extension .gvi (note, this is different than the saved Google Video Player, .gvp, file). Rename the extension to .avi.
  4. Burn this file to a CD-R disc. And it's ready to play.
Last night I used this technique to watch part of Bram Moolenaar's (of Vim fame) talk on 7 Habits For Effective Text Editing 2.0 on my DVD player from the comfort of my living room.

Wednesday, March 07, 2007

Custom Tomcat Server Location coming in Eclipse WTP 2.0

Web Tools Platform 2.0 M5 News

This looks very cool (scroll down to "Configure Tomcat's Paths"), especially for us portlet developers. It's been challenging using Eclipse WTP to run and debug portlets because WTP wants to take the Tomcat installation you provide, copy the server parts to a temporary location, and then deploy your webapp there. So it doesn't matter if the Tomcat installation you tell WTP to use has GridSphere or Pluto installed, they won't be there in the temporary location (neither the portal webapps nor shared/lib). Of course, you can manually copy the missing bits into the temp location, restart the server in Eclipse and get something working, but only after much consternation. So I happily welcome this new development and look forward to using WTP 2.0 when a final release is made.

Tuesday, February 20, 2007

Double Submit Fix with Multiple Submit Buttons

In the LEAD Portal we have a portlet that allows users to submit weather forecast workflows. When the user clicks the Launch button, a lot of things have to go on behind the scenes to setup and launch the workflow, and it's not atypical for a user to wonder if maybe something is amiss and attempt to click the Launch button again. This double submit is quite problematic for us however.

I searched the web for a double submit prevention JavaScript code, and found some good starts. But our portlet has multiple submit buttons and I found that if I disabled the Launch button after it is clicked, for some reason, that buttons name and value are not passed in the POST to the server. So I have to account for this. Here's the JavaScript I used:


<form action="${actionURL}" method="POST" name="wfParamForm">
<div align="right">
<input type="submit"
name="actionMethod_doExp_wiz" value="<>
<input type="submit"
name="actionMethod_doExp_wiz" value="Next >" disabled="yes" />
<input type="submit"
name="actionMethod_doExp_wiz" value="Cancel" />

<!-- since we have multiple submit buttons, we need to add the
name value pair of this submit button to the form action. It
seems that when the button is disabled that this also prevents
it from being present in the POST -->
<input type="submit"
name="actionMethod_doExp_wiz" value="Launch"
onClick="this.disabled=true; this.value='Please wait...'; this.form.action=this.form.action + '&actionMethod_doExp_wiz=Launch'; this.form.submit()" />
</form>


This is from a Velocity Portlet, and it is creating a wizard like interface with Back, Next, Cancel, and Launch buttons on each page of the wizard. Look at the JavaScript for the onClick for the Launch button. Pretty standard stuff (sets the Launch button to disabled, displays "Please wait.." in the button), except that it is also adding the name value pair of the Launch button to the form action. This works and has been tested with IE and Firefox.

Thursday, January 25, 2007

Scripting IFrames in IE and Firefox

Update: Found out Safari requires iframeEl.contentWindow, iframeEl.contentDocument.defaultView doesn't work (or, at least, it doesn't work any more). Turns out that this works for Firefox as well. I've left the other branch for backwards compatibility and also because it is more standard.

Here's how to get a reference to an iframe with JavaScript, in Firefox and IE, IE and Safari:


var iframeEl = document.getElementById("iframeId");
var iframeDoc = iframeEl.contentDocument
var iframeWin;
if (iframeDoc) { // Firefox
iframeWin = iframeDoc.defaultView
} else { // IE
iframeWin = iframeEl.contentWindow
}
if (iframeEl.contentWindow) { // IE and Safari require, but works for Firefox too
iframeWin = iframeEl.contentWindow;
} else if (iframeEl.contentDocument) { // Works for Firefox, DOM level 2 standard
iframeWin = iframeEl.contentDocument.defaultView;
}

And then you can use iframeWin to get access to JavaScript objects and the DOM of the iframe.

Also, I learned that getElementById() in IE (version 7 tested) picks up elements by name attribute as well, so names and ids need to be unique for all elements on a page for IE.

Monday, December 25, 2006

Parenting Hack: Disabling the auto-flushing toilet

If you are a parent of small children like myself you can probably relate to a situation that I commonly find myself in. I take our 4 year old girl to the public restroom because, well, she's gotta go. And when we get there we see that the toilet is one of those auto-flushing models, you know, with a light sensor that can tell when an adult has sat down and stood back up and hence flushes automatically. I put emphasis on adult because as you may know this doesn't always work so well with a child, especially squirmy ones. Inevitably, the toilet flushes too soon, and these tend to not be wimpy flushers either. The flushing action can remind one of Charlton Heston as Moses in the Ten Commandments parting the Red Sea. And children find this very disturbing, obviously.

Well, on a recent trip to the "facilities", I came up with a simple hack to get around this problem. Simply take a piece of toilet paper (paper towel would probably work well too) and drape it over the light sensor. The child can then safely use the toilet. After the child has dismounted and everyone is ready for a flushing of biblical proportions, remove the toilet paper from the light sensor, which will activate the flushing, and drop it into the toilet.

Happy parenting!

Thursday, December 21, 2006

Evaluating Grid Portal Security Paper, Review

I just finished reading a paper titled Evaluating Grid Portal Security, by David Del Vecchio, Victor Hazelwood and Marty Humphrey. In it they evaluate GridSphere, OGCE and Clarens against a standard set of security metrics. The conclusion is that there is plenty of "room for improvement". I found their recommendation section at the end particularly helpful. It got me to thinking about things we can do in the projects I work with to make grid portals more secure, and here I try to capture my thoughts.

First, I think in the PURSe/PURSe Portlets project, we should provide a way to configure the strength of the password required when a user creates a new registration, and we should provide a secure setting of this by default out of the box. I created a bug report to track this.

Second, I think one of the most difficult challenges for grid portals is in the area of creating, managing and processing auditing logs. But the authors do provide a simple criterion, that all grid credential accesses be written to auditing logs. However, is this sufficient? It would seem that one would need to audit also all grid services requests (e.g., GRAM and GridFTP calls). Then there is the problem of how to audit the auditing logs. Perhaps there are general purpose tools to make this more feasible. Nevertheless, we are seeing in TeraGrid a strong requirement for this functionality, so we need to come up with a solution.

For the LEAD Portal that I work on, this is complicated by the fact that we do not have the user's grid credentials at the portal level, nor do we make calls to grid services from the portal. Ours is a more distributed architecture, with services communicating asynchronously via a publish/subscribe notification broker. So what we need is an auditing notification topic that all LEAD services could write to as a kind of auditing log. A special auditing listener could be set up to listen to this topic and persist the messages to a file or database.

Tuesday, December 05, 2006

Upgrading MySQL 3.23 to 5.0

I recently had to upgrade a crufty old MySQL database on one of our Solaris machines (rainier) from 3.23 to 5.0. Here's the process I came up with. This is all in the MySQL documentation, but you have to hunt here and there for it, and what is outlined below allows you to do, or at least, test the upgrade while the original server is still running.

Preparation

Downloaded and installed latest 4.0, 4.1, and 5.0 into a directory.

Copied data directory into /usr/local/mysql-data.

Upgrade from 3.23 to 4.0

Started 4.0 pointing at this data directory, on port 3307.

Edit /usr/local/mysql-data/my.cnf to use port 3307 and socket file /tmp/mysql2.sock

cd mysql-4.0
export PATH=$PWD/bin:$PATH
mysqld_safe --defaults-file=/usr/local/mysql-data/my.cnf --user=emysql --datadir=/usr/local/mysql-data --basedir=$PWD --pid-file=/usr/local/mysql-data/rainier.pid

Check the databases:

mysqlcheck --all-databases -u root -p -h rainier -P 3307

mysql_fix_privilege_tables --user=root --socket=/tmp/mysql2.sock --password=xxxxxx

Lots of warnings and errors, but supposedly this is okay.

Didn't need to upgrade ISAM to MyISAM storage engine.

mysqladmin -u root -P 3307 -p -h rainier shutdown

Upgrading from 4.0 to 4.1.

cd ../mysql-4.1

export PATH=$PWD/bin:$PATH
mysqld_safe --defaults-file=/usr/local/mysql-data/my.cnf --user=emysql --datadir=/usr/local/mysql-data --basedir=$PWD --pid-file=/usr/local/mysql-data/rainier.pid

Check the databases:

mysqlcheck --all-databases -u root -p -h rainier -P 3307

mysql_fix_privilege_tables --user=root --socket=/tmp/mysql2.sock --password=xxxxxx --basedir=$PWD

mysqladmin -u root -P 3307 -p -h rainier shutdown

Upgrading from 4.1 to 5.0


cd ../mysql-5.0

export PATH=$PWD/bin:$PATH
mysqld_safe --defaults-file=/usr/local/mysql-data/my.cnf --user=emysql --datadir=/usr/local/mysql-data --basedir=$PWD --pid-file=/usr/local/mysql-data/rainier.pid

mysql_upgrade didn't seem to work, but I think that's because I had run it in an earlier attempt to upgrade from 3.23 to 5.0. So I did the individual steps:
mysql_fix_privilege_tables --user=root --socket=/tmp/mysql2.sock --password=xxxxxxxxx --basedir=$PWD
mysqlcheck --check-upgrade --all-databases --auto-repair -u root -p -h rainier -P 3307

I ran upgrade again, anyways, this time with the force option
mysql_upgrade -p -S /tmp/mysql2.sock --datadir=/usr/local/mysql-data --basedir=$PWD -u root --force


Additional notes:

Setting up the mysql init script. I set the datadir and the basedir, and then I added a --defaults-extra-file=$datadir/my.cnf to the line that invokes mysqld_safe.

Tuesday, November 28, 2006

Integrated Google AJAX Search with LEAD Portal

First I created a LEAD Project custom search engine:

http://www.google.com/coop/cse?cx=001503951656019931001%3Ag2lqfazq_ti

Then I signed up for a Google AJAX search key for portal-dev.leadproject.org. Google gave me some stuff to add, and it worked just fine. I set the web search site restriction to the custom search engine created above:


var searchOptions = new GsearcherOptions();
searchOptions.setExpandMode(GSearchControl.EXPAND_MODE_OPEN);

var leadWebSearch = new GwebSearch();
leadWebSearch.setSiteRestriction("001503951656019931001:g2lqfazq_ti");
searchControl.addSearcher(leadWebSearch, searchOptions);


This all worked fairly well, but I wanted a couple of other things from it. First I wanted to have the search control open up the results over the web page instead of within the web page and rearranging the layout. I found this blog entry at www.cjmillisock.com with a nice use of some simple CSS to get the right effect. Secondly, by default the search results are limited to just one. So I created a GsearcherOptions object with expanded mode set to OPEN (see the above code snippet and also the api documentation).

You can see the result at http://portal-dev.leadproject.org

Wednesday, November 01, 2006

Adding the portlet.xml schema to Eclipse

Updated 2007-04-12: Fixed the instructions. Seems the old ones don't work any longer.

I finally figured out how to do this. The inferred XML schema support in Eclipse is pretty nice and usually suffices, but sometimes I want to have completion based upon full schema knowledge. Here's how to add the portlet.xml XSD file to Eclipse:
  1. First you need to have the JSR 168 code, so go there and get it.
  2. For Eclipse you'll need WTP installed. Get Eclipse 3.2 and use Callisto Discovery Site to download WTP as well.
  3. Okay, now in Eclipse's preference window, go to Web and XML > XML Catalog. Click Add ....
  4. In the URI field, click the little arrow and select the portlet-app_1_0.xsd file that you downloaded in the JSR 168 release.
  5. In Key Type field select Schema Location. Then in the Key field, enter the schema location that you will be using in your portlet.xml files. I entered http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd.
  6. Click OK, OK.
  7. Then you need to make sure you have the following entries in the root element (portlet-app) in your portlet.xml file:
    • [Added 2007-04-12] xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
    • xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    • xsi:noNamespaceSchemaLocation="http://java.sun.com/xml/ns/portlet"
    • [Updated 2007-04-12] xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
  1. Then if you already have a portlet.xml file loaded you'll need to go to XML > Reload Dependencies. Then you should have tag completion in your portlet.xml files.
For more information, here is the corresponding entry from the Eclipse help documentation. I should note that Eclipse seems to think there are errors in the portlet xsd file, but this doesn't seem to cause any problems, i.e., the tag completion works properly.

I should note also that this approach works for other XSD files as well. I recently also used these steps to get schema support for Maven2 pom.xml files.

Friday, October 27, 2006

MyFaces JSF and GridSphere

Recently I received an email from someone who was trying to create a JSF portlet for GridSphere. This person was looking for some advice. I have only encountered one major problem with developing JSF portlets for GridSphere and that is that in GS 2.1.x MyFaces JSF portlets create invalid default id's for JSF components. The problem is that in this version of GridSphere, RenderResponse.getNamespace() returns an identifier with a "#" character in it, which is an invalid character for JSF component ids. Jason discusses this issue in the gridsphere-dev mailing list.

The simple workaround to this problem is provide id's for each of your JSF components. Here's a snippet of the kind of JSF template that works with GS 2.1.x:

<!-- FIXME: GridSphere "malformed autogenerated id" issue Below several JSF components have been given unique id's to workaround this issue in GridSphere 2.1.x. This bug has been fixed in GridSphere 2.2.x, but we're not currently using 2.2.x. Once we do move to 2.2.x we can remove all id's that are prefixed with "gsid_" -->

<f:view>
<h:form id="gsid_wrapperForm">
<h:outputtext id="gsid_greetingOT" value="Hello, #{Workspace.userFullName}, you are in your Personal Workspace">
</h:outputtext></h:form></f:view>
...

However, that gets very tedious. Fortunately this problem is fixed in GS 2.2.x, but we're not in a position in the LEAD Project to move to 2.2.x at this time (in fact, I'm holding out for GS 3.0). So I've hacked myfaces 1.1.4 to change the "#" character to "_hash_" when it gets such a value in the returned namespace. The modified jar is available in the Extreme Lab maven repository. Also, if you are using Maven 2, you can use:

<dependency>
<groupId>org.apache.myfaces.core</groupId>
<artifactId>myfaces-impl</artifactId>
<version>1.1.4-gs</version>
</dependency>

to specify the dependency, and you'll need to add the extreme repo in your <repositories> list:

<repository>
<name>Extreme Maven2</name>
<id>extreme.repo.maven2</id>
<url>http://www.extreme.indiana.edu/dist/java-repository</url>
<snapshots>
<updatePolicy>daily</updatePolicy>
</snapshots>
</repository>

This has come in very handy now that I've begun working with Facelets, which I am very happy with.

Monday, October 02, 2006

Using Maven's deploy:deploy-file to import 3rd party jars

Maven - Guide to deploying 3rd party JARs to remote repository

Usually I just manually copy in third party jars to our Maven repository when they come by, but recently I decided to give Maven's own tools a try. In this example, I'm deploying a MyLEAD jar Scott Jensen has sent my way:


mvn deploy:deploy-file -DgroupId=mylead -DartifactId=mylead-crosscut-attr \
-Dversion=1.0 -Dpackaging=jar -Dfile=./mylead_crosscut_attr-1.0.jar \
-Durl=scpexe://rainier.extreme.indiana.edu/l/extreme/java/repository

And here, I deploy it again, but this time as a Maven1 type artifact, to support Maven1 clients:


mvn deploy:deploy-file -DgroupId=mylead -DartifactId=mylead-crosscut-attr \
-Dversion=1.0 -Dpackaging=jar -Dfile=./mylead_crosscut_attr-1.0.jar \
-Durl=scpexe://rainier.extreme.indiana.edu/l/extreme/java/repository \
-DrepositoryLayout=legacy

Monday, September 25, 2006

Using service certificates with Globus Java APIs (jglobus)

Anne Wilson of Unidata recently contacted me about using grid credentials for a long running service. I suggested that she use "service certificates" (definition), but I didn't know exactly how to use them from an application using Java CoG. I looked it up but looks like Anne already has a way to do this or something similar, so I just want to make a quick note about how to do this for future reference.

In jglobus there's the GlobusCredential class. To create a GlobusCredential object from a service certificate (or, more generally, from a certificate/private key pair where the private key is not encrypted), the constructor you use is GlobusCredential(String certFile, String unencryptedKeyFile). From there, it's a little unclear but it seems that you can get a GSSCredential from this by then creating a GlobusGSSCredentialImpl object with the arguments (GlobusCredential, int usage) where it seems a good value for usage would be GSSCredential.INITIATE_AND_ACCEPT.

You would use this approach when you need a service with Globus credentials but you don't want to or can't create a proxy certificate for it over and over again.

Tuesday, September 05, 2006

Getting commons-logging to behave in Tomcat

Commons-logging is the bane of my existence, and I only use log4j now in all of my new projects. Unfortunately, I don't have the luxury of completely avoiding it since several projects I depend upon use it. Hence, I've found a simple little way to get commons-logging out of my way when working with web applications in Tomcat. The basis of the trick is to get commons-logging to stop trying to auto-discover the log4j configurations I'm using. So I drop a commons-logging.properties file in the top-level of the classloader hierarchy ($CATALINA_HOME/common/classes) that directs commons-logging to use its own built in SimpleLog facility.


org.apache.commons.logging.Log = org.apache.commons.logging.impl.SimpleLog


Then I add a properties file, simplelog.properties, in the same directory to configure the SimpleLog logger.


org.apache.commons.logging.simplelog.defaultlog=warn
org.apache.commons.logging.simplelog.log.org.apache.myfaces=debug
org.apache.commons.logging.simplelog.log.org.globus.purse=debug


Here I've set MyFaces and PURSe, a Grid security library I use, logging levels to DEBUG. Of course, I have to make sure that I have a commons-logging.jar in common/lib. This setup has been working pretty well for me for some time.

Friday, September 01, 2006

Top 10 Coolest Things coming in JSR 286

A while back I posted on the availability of JSR 286 Early Draft 1 (just a reminder that today is the last day to get feedback to the JSR 286 group on this early version of the specification). Recently I finished reviewing it and here is a list of what I found to be the most interesting new things coming in JSR 286.

  1. Portlet Events - Yes, they are finally here. Portlets can consume and produce events. This is a very important addition because portals can only handle one action request from one portlet at a time, even though other portlets on the page might want to respond to that action. With JSR 286 they will be able to do this. One thing that is unclear from the specification is the scope of portlet events, i.e., are they broadcasted across all portlets in a page, all portlets within that portlet application, or across all of a user's portlets?
  2. CSS Style Diagrams - Now we can see what the standard CSS portlet styles are supposed to be used for. Okay, it's not a fantastically cool thing, but I'm very happy to see that the JSR 286 group has addressed one of my pet annoyances with JSR 168, that the CSS portlet styles are described only with ambiguous text. And ambiguity makes the standard styles hardly worth the trouble of using, but this is a very important aspect of portability and reusability for Java Portlets.
  3. Shared Session Attributes - Finally, sessions with portal scope! This seems like the most obvious thing to have in a Java Portlet specification I was dismayed to see if missing from JSR 168. One obvious use case for this would be the loading of session objects that other portlets could use for the purpose of "single sign on" in the portal. In the grid portals I've worked with, we load the user's grid proxy credential at log in and need a way to make it available to other portlets. We had resorted to ad hoc singleton style services higher up in the classloader hierarchy in Tomcat. Now we can have a real solution. One interesting point here is that in Early Draft 1, the JSR members specifically ask for input on whether this feature is needed given that you can accomplish the same sort of thing with Portlet Events. It's my opinion that it should be provided, because sometimes you want user attributes in the user's session that aren't necessarily event oriented.
  4. Filters - Like their servlet cousins, portlets now have filters. I've yet to think of a need I have for portlet filters, but now that we'll have them, I'm sure some ideas will come to mind.
  5. Resource Serving - This is a nice feature. This sort of thing is possible in JSR 168 by including servlets with your portlet application that could serve up things like images or JNLP (you know, those WebStart descriptors) documents. But then things were a little bit trickier in that to parameterize those servlet requests you would have to add attributes to the APPLICATION_SCOPE session in your portlet that would later be read by the servlet. Note also that JSR 286 mentions that this would be the way to service AJAX requests.
  6. Use of Annotations - This Java 5 feature is being used to route Event requests to the appropriate event handling method in processEvent(). Oddly, Early Draft 1 doesn't mention that the same will be done for routing action requests to various action methods. I've done this kind of routing in the VelocityPortlet bridge I wrote, using reflection. The annotation idea looks pretty cool and probably cleaner.
  7. More Support for AJAX - The focus of Early Draft 1 is "portlet coordination" and "WSRP 2.0 interoperation", so there isn't much that is AJAX specific here, but we are promised that more is on the way (such as state changing resource serving requests).
  8. Shared Render Parameters - I didn't see this one coming, and I have to admit I'm still trying to figure out how I would best use this. The idea is that when a portlet sets a render parameter this parameter could be shared with other portlets. The outcome of this is that when you select an account to view in the "Accounts List" portlet (invoking a portlet action), the "Accounts List" could set the currently_selected_account render parameter which would cause that account to be highlighted in "Accounts List" (on the render phase). If this render parameter is shared, then the "Account Detail" portlet on the same page could also see this parameter and, since its doView() but not it's processAction() method would be called, it could then update its display with details about that selected account. You can do the same sort of thing with session objects, but this is probably a cleaner way of doing it.
  9. Portlets aren't just for Portals anymore - I love this quote:
    The predominant applications using portlets today are portals aggregating the portlet markup into portal pages, but the Java Portlet Specification and portlets itself are not restricted to portals.
    With JSR 286, I think Java Portlets have the potential to really remake the Java web development scene. Portlets can and in many cases should be applied to non-portal environment.
  10. JAXB! - Okay, I'm stretching this top ten list a bit. JAXB is leverage in this specification as a way to define payload data for event and shared session attributes. So it looks like I'll need to learn me some JAXB. If you know a good tutorial, let me know.

Monday, August 21, 2006

Fixing Out of Memory Errors with Eclipse 3.2, Mac OS X

I've recently been getting out of memory errors with Eclipse 3.2 on Mac OS X. Initially, I bumped the maximum heap size to 512MB, but that wasn't sufficient. I then saw that the problem was actually with the PermGen size. So I bumped that up from the default 64MB to 128MB. So far so good.

On OS X, you change these settings by editing Eclipse.app/Contents/MacOS/eclipse.ini. There I set -Xmx to 512m and I added a parameter, -XX:MaxPermSize, and set it to 128m. My complete eclipse.ini file is here:


-vmargs
-Xdock:icon=../Resources/Eclipse.icns
-XstartOnFirstThread
-Xbootclasspath/p:../../../plugins/org.eclipse.jdt.debug_3.2.0.v20060605/jdi.jar-Xms40m
-Xmx512m
-XX:MaxPermSize=128m
-Dorg.eclipse.swt.internal.carbon.smallFonts
-Dorg.eclipse.swt.internal.carbon.noFocusRing

Wednesday, August 09, 2006

PURSe Portlets v. 1.0.1 released

PURSe Portlets 1.0.1 Release Notes

Hot off the press, just put this release together. I got a lot of feedback on the 1.0 release, from within the LEAD project and from folks outside the LEAD project. All discovered bugs, more or less, have been fixed in this release. Enjoy!