Monday, December 13, 2010

Using JBoss with Portlet Factory

On several projects I've had to develop portlets using WPF that are deployed to a Websphere Portal environment, but the options for executing in a development environment are a little limited. I can choose Websphere CE, Websphere Portal or Tomcat, and my first choice is usually Tomcat because it has a small footprint and fires up quickly. But in some cases I need to test some portal specific features like wiring or portlet configuration, and this requires a portal server. Websphere Portal is great for a production environment, but running it locally is not practical since it takes so many resources and has a long startup time.

Running JBoss

At one point I was really under pressure to get some work done and I finally gave up on Websphere Portal and turned to JBoss Portal Server (looks like that project has been merged into project Gateln). Unfortunately WPF doesn't have a configuration option for JBoss so I had to roll my own.

Step 1
The platform definitions that show up in the project properties originate from files located in \IBM\Portlet Factory\Designer\FeatureSets\Web-App_7.0.0\Deployment\antscripts\platformdefs (or wherever WPF is installed). All I need to do is add my own file called JBoss.pfConfig, which is a copy of the Tomcat file looks something like this:
wpf.installedappsdir=C:\jboss-portal-2.7.2\server\default\deploy
wpf.serverport=8080
wpf.serverUrl=localhost
wpf.servertype=appserver
wpf.servername=JBoss
wpf.config.antfile=JBoss.xml
wpf.config.publishtarget=publishJBoss
wpf.webxml.file=standalone.web.xml
wpf.autodeploy=false
wpf.configid=3
wpf.description=CreateServerDialog.TomcatDescription


Step 2
The pfConfig refers to an ant file JBoss.xml which lives in \IBM\Portlet Factory\Designer\FeatureSets\Web-App_7.0.0\Deployment\antscripts\publish. Here again I copy from the Tomcat version and make a few changes:
<!--Ant implementation for deploying to JBoss server.-->

<project name="jboss" basedir=".">
 <!-- Target for deploying project to JBoss server. -->
 <target name="publishJBoss">
  <echo message="Publishing to JBoss server..." />

  <!-- Copy project contents to server. -->
  <copy todir="${wpf.installedappsdir}/${project.name}.war" preservelastmodified="yes">
   <fileset dir="${webcontent.location}">
    <include name="**/**" />
    <excludesfile name="${webcontent.location}/.excludeFromServer" />
    <excludesfile name="${webcontent.location}/../.deployment/excludes/allServers.excludes" />
    <excludesfile name="${webcontent.location}/../.deployment/excludes/JBoss.excludes" />
   </fileset>
  </copy>

  <!-- Copy the standalone web.xml file to the server. -->
  <copy file="${webcontent.location}/WEB-INF/bin/deployment/standalone.web.xml" tofile="${wpf.installedappsdir}/${project.name}.war/WEB-INF/web.xml" />


 </target>
</project>
This is the script that the designer will invoke when publish application (V7) or build war for dev testing (V6.1.2) is selected.

Step 3
Well actually there is no step 3, I think that's all that is needed. When I look at my project properties I can now see JBoss as an available server:


There are a few caveats:
- In some earlier versions of WPF, the designer treats the JBoss configuration like Tomcat and strips off the .war file extension. Every time I explicitly deploy I get an error message and have to go back into the properties and put the extension back on. This doesn't happen when auto sync runs, only when an explicit deploy is requested.
- In WPF V7 the designer will complain about a missing exclude file the first time. Just add an empty file named \myproject\.deployment\excludes\jboss.excludes.

Wednesday, December 8, 2010

Sunday, December 5, 2010

Debugging Javascript with a Reverse Proxy

A few months ago I was exploring the possibility of integrating IBM's Lotus Sametime instant messenger into an installation of Websphere Portal 7 and I had to test some cross domain javascript. As we all know, modern browsers won't allow a javascript request to access a domain which is different from the current.

In this case the javascript provided by the sametime proxy server (running on a different node) contained relative URLs, like /stwebapi/..... Now this is not an issue when running in a production environment because we have a Webseal reverse proxy, but if you need to debug some code on a local machine then you're out of luck. The browser won't issue cross domain javascript requests.

Using Apache as a Reverse Proxy

Turns out that with a few configuration tweaks I can use apache as a reverse proxy. I added the following lines to the bottom of my \Apache2.2\conf\httpd.conf :

ProxyRequests Off

Order deny,allow
Allow from all

ProxyPass /stwebapi http://ghprd01:9081/stwebapi
ProxyPassReverse /stwebapi http://ghprd01:9081/stwebapi

So now any requests to /stwebapi will be redirected to by apache to http://ghprd01:9081/stwebapi, and as far as the browser knows it all comes from the same domain.

Piece of cake!

Wednesday, December 1, 2010

Add Toolbar Plugins to Dojo Rich Text Editor Builder

Websphere Portlet Factory (WPF) has been incrementally adding dojo features to their product over the last few releases. I recently assessed the dojo rich text editor to see how it compared to the features in sharepoint 2010, and found that it has a few tricks that can trump it (at least in the context of my evaluation).

Hidden Plugins

The dojo rich text editor builder provides several check boxes to enable a number of tools on the toolbar, but some sleuthing in the factory\dojo\dijit\_editor\plugins directory revealed some more tools. Dojo's rich text editor provides a plugin mechanism to add tools to the toolbar so I decided to experiment with FullScreen.js. Since we don't have a check box for this in the builder, I'm going to add it directly using javascript:

<span name="richTextEditorGoesHere"/>

<script type="text/javascript"> 
gcps.assessmentWidget = '<%= IDGenerator.getCurrentID(webAppAccess, "inline_widget") %>';

dojo.addOnLoad(function(){
    dojo.require("dijit._editor.plugins.FullScreen");
    var widget = dijit.byId(gcps.assessmentWidget);
    widget.addPlugin('fullscreen');
});
</script>

WPF generates the value for ID attributes, so I had to use a call to IDGenerator.getCurrentID to get my hands on that value and store it. The value inline_widget is static and is what the builder uses internally, take a look at the source tab in the designer and you'll see what I mean. It is important to put this script immediately after the placeholder for the builder richTextEditorGoesHere or it won't work.

If we run our model we should now see a new icon on the toolbar which will cause the rich text editor to maximize when clicked:


I think that covers all the details, pretty cool stuff! I wish the guys at IBM would have put this in the builder, but we can still work around it.