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.

Monday, November 29, 2010

Facebook Tracking Your Every Move

I've recently become aware that facebook tracks all of my browsing activities, even when I'm not on the facebook site. It turns out that every web page that contains a facebook 'like' button is also capable of tracking your visit to the page if you're logged into facebook, even if you haven't explicitly clicked that button.

Blocking Facebook

I'm not a big fan of giving away information, particularly to large corporations that have loose privacy policies, so I do what I can to prevent this kind of tracking. Step one in this case is always logging out of facebook when I'm done with a session (I've largely stopped posting to facebook anyways), but I've also gone the extra step and added it to my firefox ad blocking plugin. The ad blocker works by filtering out a list predefined URLs in an HTML document that refer to ads, the net result is an ad-free web browsing experience.

Adding *facebook* to the list of URLs enables me to ultimately block any communication with facebook servers unless I explicitly allow it. I suppose this technique could be used for any website.

Wednesday, November 17, 2010

Finding a Missing Java Class at Compile Time

As a developer I've run into this scenario many times - my code won't compile because of a missing reference to some third party class in some JAR file that I can't possibly find.

On many occasions I've used findjar. Just pop in the class name that the compiler is complaining about and this handy site will not only tell you which JAR it lives in, but will also provide a link to the location it can be downloaded.

But today I ran into a more difficult case. Findjar doesn't work well with proprietary JARs like those found in IBM's Websphere Portal Server. I remember a long time ago reading about a utility that could find a JAR file by loading up a given classpath and quickly finding a class on that path.

A quick google search yielded something even better, Jarscan. Jarscan is a utility that will scour a given path on your filesystem, collecting all the JARs it finds and then tells you where your elusive class lives.

Monday, November 15, 2010

Using The Repeated Region builder

I recently encountered a case where I needed to display some repeating xml data that was embedded in a larger xml structure, something that the data page builder doesn't do well. So I decided to take a look at the repeated region builder, and found out that as with many builders, the correct inputs aren't so easy to figure out.

The data in a variable builder (varData) :
 <dsixe>  
   <contact>  
     <name></name>  
     <phone></phone>  
   </contact>  
   <order>  
     <item>  
       <id>1234</id>  
       <descr>Item one</descr>  
       <upc>DC88776</upc>  
     </item>  
     <item>  
       <id>3456</id>  
       <descr>Item two</descr>  
       <upc>DC88773</upc>  
     </item>  
     <item>  
       <id>3458</id>  
       <descr>Item three</descr>  
       <upc>DC88774</upc>  
     </item>  
   </order>  
 </dsixe>  

Note that <contact> is a sibling element of <order>, but we're not interested in that. What we want is just a list of orders with the ID hyperlinked to a URL which uses the UPC code as a parameter.

Page builder contents:
 <html>  
   <head><title>Default Test Page</title></head>  
   <body>  
           Orders:<br>  
           <table>  
                <tr name="repeatRow">  
                     <td><span name="id"/></td>  
                     <td name="descr"/>  
                </tr>  
           </table>  
   </body>  
 </html>  

Produces:
Orders: 

1234 Item one
3456 Item two
3458 Item three

The repeated region builder is designed to handle this exact scenario, the difficulty comes in defining the correct input values for the builder.


Note that the source data input field points to varData/dsixe/order and not varData/dsixe/order/item. The key piece of information here is the loop variable name (dsixeLoopVar) which is used in other builders to refer to values which are repeated. I think the reason this builder is difficult to use is due to the fact that this variable name doesn't show up as expanded in the variable pickers, it has to be manually typed in.
Also note how the page location repeatRow is a table row and identifies what chunk of HTML will be repeated.

Let's add a text builder to display the descr element:


In this case I was able to select ${Variables/dsixeLoopVar} from the picker and then type /item/descr on the end.

Hope someone finds this useful!

Creating Web Services for Portlet Factory

The heart of any SOA strategy involves web services and the document that makes it happen is a WSDL. Websphere Portlet Factory is an excellent tool for putting together a SOA presentation layer since it easily accepts a WSDL and quickly exposes its operations in a developer friendly IDE (Eclipse/RAD).

In previous WPF projects I'd start by building out schema that represent the data needed for display in the tool, but when working with web services the schema is defined in the WSDL document. Since I dislike working with schema, I typically create a sample XML and then use a tool to generate a schema from it. But what about the schema that are in the WSDL? What if I'm also developing the web services that will be ultimately consumed by WPF? I sure don't want to create a schema when something else can do the dirty work.

Enter web services metadata annotations (JSR 181).

Using annotations and a compatible runtime container like Apache's Axis2, I can throw together a web service in no time by just adding some annotations to a regular POJO. Suppose I have a need to retrieve contact information, but no implementation is available yet and I just need something stubbed out so I can get going. Someone else can follow up later and code in an implementation.

Let's start with a bean that will hold our contact information:

 package com.dsixe.blog;  
 public class ContactBean {  
      private String name;  
      private String phone;  
      public String getName() {  
           return name;  
      }  
      public void setName(String name) {  
           this.name = name;  
      }  
      public String getPhone() {  
           return phone;  
      }  
      public void setPhone(String phone) {  
           this.phone = phone;  
      }  
 }  

The only code needed here is the declaration of the name and phone, the rest (class definition, getters/setters) is generated by Eclipse. Now let's create a POJO that will ultimately contain the implementation of the operation, but for right now it will just return a static instance of ContactBean:

 package com.dsixe.blog;  
 public class ContactInfo {  
      public ContactBean getContact(String uid){  
           ContactBean cb = new ContactBean();  
           cb.setName("Carl");  
           cb.setPhone("678 555-1212");  
           return cb;  
      }  
 }  

Nothing magical about this class, but it can be turned into a web service operation by adding 3 annotations:

 package com.dsixe.blog;  
 import javax.jws.WebMethod;  
 import javax.jws.WebService;  
 import javax.jws.soap.SOAPBinding;  

 @WebService(serviceName="ContactService", targetNamespace="http://dsixe.com/blog")  
 @SOAPBinding(style=SOAPBinding.Style.DOCUMENT)  

 public class ContactInfo {  
      @WebMethod  
      public ContactBean getContact(String uid){  
           ContactBean cb = new ContactBean();  
           cb.setName("Carl");  
           cb.setPhone("678 555-1212");  
           return cb;  
      }  
 }  

Believe it or not, that's it! I package it into a JAR (not a WAR) and deploy to Axis2 and I'm ready to pull a WSDL into a WPF web service builder.

In the time it probably would have taken me to build an XSD schema using some fancy editor, I've not only created a WSDL with the required schema but also a functional base implementation of a service operation.