Arch2Arch Tab BEA.com

Gerald Nunn's Blog

Gerald Nunn's Homepage
Gerald Nunn is a business principal consultant with BEA Systems Professional Services. He is married with a four year old son and lives in Newmarket, Ontario, Canada.

Blog Moving Day

Posted by gnunn on May 31, 2008 at 6:26 PM | Permalink | Comments (0)

With the recent of acquisition of BEA by Oracle, change is in the air. While I am pleased to say that I will be continuing on to Oracle my blog will not. It is moving to a new site and can be found at http://www.gexperts.com/blog/blog.html so please be sure to update your links and bookmarks if you wish to continue following my work. I plan on continuing to blog about WebLogic and WebLogic Portal but will also be blogging about some new topics as well. Hope to see you there.



Best Practices for Links in WebLogic Portal

Posted by gnunn on April 4, 2008 at 6:12 AM | Permalink | Comments (0)

Introduction

A question that comes up from time to time is what is the best practice with respect to the format of URLs within links in a portlets. By links, we mean both links used in anchor tags and used when accessing resources, for example the src attribute in the img tag.

First a little background, there are three main styles used to construct a link in a web application. These are:

  • Absolute. This is a link that contains the full URL including the scheme (http or https), domain and port. For example, http://www.yahoo.com/finance would be an example of an absolute link.
  • Relative. This is a link that is relative to the current document, for example ../images/someimage.jpg.
  • Root Relative. This is a variant of the relative style link, in this case the link is relative to the root of the web application. Links of this nature always start with a slash followed by the application's context root. An example of a root relative link would be /application/framework/skins/myskin/images/someimage.jpg where application is the context root of the web application.

Portal Links

When constructing links in WebLogic Portal the best practice in my opinion is to use root relative links. The problem with absolute links is that it can be difficult for the application to accurately determine what the front end scheme, domain and port is given the amount of infrastructure that could potentially be sitting between the WebLogic Portal server and the user's browser. This gets even more complicated to manage if users will access the site from different front ends. A root relative link eliminates this issue by leaving it to the browser to determine these parameters based on the URL of the current document.

Relative links have a different issue in that they are incompatible between a file mode (.portal) portal and a streaming desktop portal. In a file mode portal, the URL will look something like http://www.someserver.com/myapplication/myportal.portal. Therefore any relative links in the portal will be resolved against the http://www.someserver.com/myapplication address. Thus if you have a relative link of images/someimage.jpg the actual URL used by the browser to retrieve it is http://www.someserver.com/myapplication/images/someimage.jpg.

Now if you take that same code and run it in a streaming desktop you have a problem. A streaming desktop has a URL like http://www.someserver.com/myapplication/portal/desktop which means the previous link now gets resolved as http://www.someserver.com/myapplication/portal/desktop/images/someimage.jpg. Of course this will fail since the image cannot be found in that location.

Root relative links solve both issues rather neatly and are thus the best choice to use. One thing to keep in mind is that if you are constructing the URL manually make sure not to hard code the context path in the link. You should use the request.getContextPath() method or an equivalent so that if the context path of the application changes none of your links will break.

There is one minor exception to this and that is with respect to CSS files. A CSS file will often contain a link to an image, for example a background-url element that specifies the image to use for the background of an object. I prefer making these links relative instead of root relative for the simple reason that there is no easy way to dynamically insert the application's context path into the CSS. This is OK because the issue of file mode versus streaming mode portal URLs does not apply here, links in a CSS file are resolved according to the location of the CSS file not the document that referenced the CSS file. As a result the URL of the portal has no bearing on resolving image links within a CSS file.

beehive-url-template-config.xml

Staying with this discussion, those of you who have worked with Portal 9.2 or 10 know there is a file called beehive-url-template-config.xml that controls how Portal rewrites links. This template by default specifies that URLs be created as absolute links. This works well in simpler environents, but in more complex environments problems can occur when the Portal cannot properly deduce the correct parameters to use when building the absolute elements of the URL.

One option to work around this issue would be to hard-wire elements of the template file. For example, instead of using the {scheme} parameter simply hardwire in https instead if the portal is always accessed through SSL. This can work, but requires the creation of deployment plans when the absolute elements vary from environment to environment, for example differences between a test and a production environment. It can also be problematic when the portal can be accessed through multiple front ends, for example internal users go through a non-secure URL while external users go through a secure URL.

An alternative solution is to simply use a root relative version of the beehive-url-template-config.xml file. In this way we leave it to the browser to determine the scheme, domain and port based on the current URL. To make this change, switch to the merged projects view of your portal web application. Under WEB-INF, right click the beehive-url-template-config.xml file and select copy to project. Now edit the file to remove the scheme, domain and port from all entries. Here is an example of what the file looks like after the changes.

<?xml version="1.0" encoding="UTF-8"?>
<url-template-config xmlns="http://beehive.apache.org/netui/2004/server/url-template-config"
                     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                     xsi:schemaLocation="http://www.bea.com/servers/weblogic/url-template-config/8.0 url-template-config.xsd">

    <url-template>
    	<name>default</name>
    	<value>
    		/{url:path}?{url:queryString}{url:currentPage}
    	</value>
    </url-template>
    <url-template>
    	<name>default-complete</name>
    	<value>
    		/{url:prefix}/{url:path}?{url:queryString}{url:currentPage}
    	</value>
    </url-template>
    <url-template>
    	<name>portlet-default</name>
    	<value>
    		/{url:path}?{url:queryString}{url:currentPage}
    	</value>
    </url-template>
    <url-template>
    	<name>portlet-secure-default</name>
    	<value>
    		/{url:path}?{url:queryString}{url:currentPage}
    	</value>
    </url-template>
    <url-template>
    	<name>portlet-action</name>
    	<value>
    		/{url:path}?{url:queryString}{url:currentPage}
    	</value>
    </url-template>
    <url-template>
    	<name>portlet-secure-action</name>
    	<value>
    		/{url:path}?{url:queryString}{url:currentPage}
    	</value>
    </url-template>
    <url-template>
    	<name>portlet-resource</name>
    	<value>
    		/{url:path}?{url:queryString}
    	</value>
    </url-template>
    <url-template>
    	<name>portlet-secure-resource</name>
    	<value>
    		/{url:path}?{url:queryString}
    	</value>
    </url-template>

    <!-- Templates for consuming remote portlets -->
    <url-template>
        <name>wsrp-default</name>
        <value>
            /{url:path}?{url:queryString}&wsrp-urlType={wsrp-urlType}&wsrp-url={wsrp-url}&wsrp-requiresRewrite={wsrp-requiresRewrite}&wsrp-navigationalState={wsrp-navigationalState}&wsrp-interactionState={wsrp-interactionState}&wsrp-mode={wsrp-mode}&wsrp-windowState={wsrp-windowState}&{weblogic-passthru}
        </value>
    </url-template>
    <url-template>
        <name>wsrp-secureDefault</name>
        <value>
            /{url:path}?{url:queryString}&wsrp-urlType={wsrp-urlType}&wsrp-url={wsrp-url}&wsrp-requiresRewrite={wsrp-requiresRewrite}&wsrp-navigationalState={wsrp-navigationalState}&wsrp-interactionState={wsrp-interactionState}&wsrp-mode={wsrp-mode}&wsrp-windowState={wsrp-windowState}&{weblogic-passthru}
        </value>
    </url-template>
    <url-template>
        <name>wsrp-blockingAction</name>
        <value>
            /{url:path}?{url:queryString}&wsrp-urlType=blockingAction&wsrp-url={wsrp-url}&wsrp-requiresRewrite={wsrp-requiresRewrite}&wsrp-navigationalState={wsrp-navigationalState}&wsrp-interactionState={wsrp-interactionState}&wsrp-mode={wsrp-mode}&wsrp-windowState={wsrp-windowState}&{weblogic-passthru}
        </value>
    </url-template>
    <url-template>
        <name>wsrp-render</name>
        <value>
            /{url:path}?{url:queryString}&wsrp-urlType=render&wsrp-url={wsrp-url}&wsrp-requiresRewrite={wsrp-requiresRewrite}&wsrp-navigationalState={wsrp-navigationalState}&wsrp-interactionState={wsrp-interactionState}&wsrp-mode={wsrp-mode}&wsrp-windowState={wsrp-windowState}&{weblogic-passthru}
        </value>
    </url-template>
    <url-template>
        <name>wsrp-resource</name>
        <value>
            /{url:path}/resource?{url:queryString}&wsrp-urlType=resource&wsrp-url={wsrp-url}&wsrp-requiresRewrite={wsrp-requiresRewrite}&{weblogic-passthru}
        </value>
    </url-template>
    <url-template>
        <name>wsrp-secureBlockingAction</name>
        <value>
            /{url:path}?{url:queryString}&wsrp-urlType=blockingAction&wsrp-secureURL=true&wsrp-url={wsrp-url}&wsrp-requiresRewrite={wsrp-requiresRewrite}&wsrp-navigationalState={wsrp-navigationalState}&wsrp-interactionState={wsrp-interactionState}&wsrp-mode={wsrp-mode}&wsrp-windowState={wsrp-windowState}&{weblogic-passthru}
        </value>
    </url-template>
    <url-template>
        <name>wsrp-secureRender</name>
        <value>
            /{url:path}?{url:queryString}&wsrp-urlType=render&wsrp-secureURL=true&wsrp-url={wsrp-url}&wsrp-requiresRewrite={wsrp-requiresRewrite}&wsrp-navigationalState={wsrp-navigationalState}&wsrp-interactionState={wsrp-interactionState}&wsrp-mode={wsrp-mode}&wsrp-windowState={wsrp-windowState}&{weblogic-passthru}
        </value>
    </url-template>
    <url-template>
        <name>wsrp-secureResource</name>
        <value>
            /{url:path}/resource?{url:queryString}&wsrp-urlType=resource&wsrp-secureURL=true&wsrp-url={wsrp-url}&wsrp-requiresRewrite={wsrp-requiresRewrite}&{weblogic-passthru}
        </value>
    </url-template>
</url-template-config>


WebLogic Portal Analytics API

Posted by gnunn on April 1, 2008 at 4:38 PM | Permalink | Comments (0)

WebLogic Portal has supported the collection of analytics for a few versions now through the Aqualogic Analytics product. A new feature in 10.2 though is that the way these analytics are collected are now exposed through a public API in the com.bea.netuix.servlets.controls.analytics package. While this has just been documented, the APIs are available in earlier versions of WLP 10 as well.

While someone could go hog wild and provide the equivalent functionality of the Aqualogic Analytics package, there are a host of other useful functions that can be driven off of these metrics. For example, the metrics could be used to monitor SLAs and trigger a warning if a specific portlet's response times starts to exceed agreed upon SLAs. Another use case would be to provide debug information at development time to allow developers to get an idea of the relative performance level of a portal and its associated portlets.

It is this latter example that we will build here. The example is a simple shared library that you can plug into a WebLogic Portal application to collect analytics on the Portals in your application. Here is a screenshot of the application, click on the image to see it full-size.

NOTE - this is only an example, it is not BEA supported code and should not be deployed into production environments. In other words, don't blame me if you try to use this in production and find issues <g>.

To use the analytics package, we first need to create a class that implements the AnalyticEventHandler interface. This is a simple class that defines a handful of methods, here is an example implementation.

public class AnalyticsHandler implements AnalyticEventHandler {

    public AnalyticsHandler() {
    }

    public void init() {
    }

    public void dispose() {
        AnalyticsManager.clear();
    }

    public void log(AnalyticEvent event) {
        AnalyticsManager.logEvent(event);
    }
}

The handler has three methods. The first method, init, is called once to initialize the handler and enables the handler to acquire any resources it may need. The second method, dispose, is called to allow the handler to dispose of any resources it has acquired.

The final method is called whenever an analytic event occurs that the handler may wish to aggregate or collect. This method is called often and as a result when implementing the handler it is very important to ensure that this method is well optimized so has not to impact the performance of the Portal. In our example above we delegate the handling of the AnalyticEvent to another class, for the purposes of this explanation I'm not going to get into the details of aggregating the statistics but you can view the source code attached to this entry for details if you wish.

The AnalyticEvent class contains a variety of information including the times for various lifecycle phases of the portlet. The lifecycle phases are pretty clear, the only confusing aspect is that there does not appear to be a phase for handlepostback but in fact handlepostback corresponds to the loadstate lifecycle so it is present. While not covered in the javadoc, the times returned by the methods in this class are in nano-seconds.

To install our handler, we need to add a file called com.bea.netuix.servlets.controls.analytics.AnalyticEventHandler in the classpath in the path META-INF\services. This file contains a single entry which is the class of the handler, for example:

com.bea.ps.portal.analytics.AnalyticsHandler

Now that our handler is installed we are ready to start getting some analytics. I have attached a pre-built library, bea-ps-analytics-1.0.0.war, that you can use to try this out. After downloading the library, add it as a shared library to your application. To do this in a development environment, go to Windows|Preferences in Workshop and expand the WebLogic node. There should be a secondary node called J2EE Libraries, click on this and add the bea-ps-analytics-1.0.0.war file.

Next in your portal WAR project, expand the WebLogic Deployment Descriptor node and right click the J2EE Libraries node. From the popup menu select the Add option and add the bea-ps-analytics library to the application. One caveat here, this will change your weblogic.xml file so make sure not to check this file into your SCM otherwise you may end up with a dependency on this library in production which you do not want to do.

Now that the library has been added, start your server and go to the URL http://localhost:7001/{portalApp}/analytics/index.jsp where you replace the {portalApp} token with the context root of your portal application. You should now see the analytics screen, click the Enable button to turn on the analytics. Open a new browser to your portal and start clicking around, come back to the analytics screen and click the Refresh button. You should see the various metrics displayed for the time you clicked around.

That about covers it, I have attached the source code to this entry for readers that may be interested in how this works in more detail. Please do remember that this is unsupported code and is not intended for use in production environments.

Shared Library: bea-ps-analytics-1.0.0.war

Source Code: bea-ps-analytics-1.0.0.zip



Using Maven and CVS on Windows

Posted by gnunn on March 17, 2008 at 9:04 AM | Permalink | Comments (0)

I am currently using Maven with CVS on a Microsoft Windows environment and had a minor issue with the Maven changlog plugin. This plugin builds a report from your CVS, or other SCM, repository that displays a list of changes made in the repository.

The issue I had was that this plugin ran fine on the Unix build box but not on my local development station that was running Windows. While not a pressing issue, it was annoying because I could not run the mvn site command locally to test any site changes out. Every time I ran the command I would get an exception about no credential being found. I had run the cvs login command previously but the plugin stubbornly refused to work even though using CVS directly at the command line worked fine. Unfortunately the client does not allow an anonymous user so the only way to get this working is to authenticate successfully.

Turns out the issue is that on Windows I was using the cvsnt binaries and there is one significant difference between CVSNT and CVS with respect to cvs login. Under CVS, when you run the cvs login command, it generates a .cvspass file that is placed in your user directory. The CVSNT binaries though place the credential in the registry. The Maven SCM plugins work with CVS directly and do not use binaries so it expects the standard CVS behavior of using the .cvspass file.

The Maven 1.x changelog plugin did have a way to generate this .cvspass file but this goal does not exist in 2.x. Therefore to generate this file I simply created a quick and dirty ANT build.xml that runs the cvspass task. Here is the build file I created:

<project name="cvspass" default="cvspass">
  <target name="cvspass">
    <cvspass cvsroot=":pserver:${username}@x.x.x.x/apps/cvs/cvsroot"
      password="${password}"
    />
  </target>
</project>

The username and password are picked up from the command line when this task is run. Being lazy, I simply run a setDomainEnv.cmd in a WebLogic domain I have lying around to initialize ANT. Afterwards, to run the ANT task simply execute the following at a command line:

ant cvspass -Dusername=xxxxx -Dpassword=xxxxx

With the .cvspass in place the mvn site command now works fine in all locations.



Yet even more on the WLP ResourceProxyServlet

Posted by gnunn on March 14, 2008 at 5:35 AM | Permalink | Comments (0)

While I have blogged about the ResourceProxyServlet a couple of times, a little recap never hurts to set the stage. As many of you know, the ResourceProxyServlet is used in WSRP to proxy resources on the producer through the consumer to the browser. Essentially it provides a means for the browser to see resources on the producer even if the producer is behind a firewall by using the consumer a proxy.

Recently the client I was working with was having an issue where requests in a federated portal were taking a long time to complete and I thought it would be useful to talk about the experience to aid others who may encounter a similar problem. Using FireBug it was easy to see that the resource requests were timing out for some reason. Looking at the log we could see the following exception occurring a short time after the request:

java.net.ConnectException: Tried all: '1' addresses, but could not connect over HTTP to server: 'xxx.xxx.xxx.xxx', port: 'xxxxx'
        at weblogic.net.http.HttpClient.openServer(HttpClient.java:361)
        at weblogic.net.http.HttpClient.openServer(HttpClient.java:430)
        at weblogic.net.http.HttpClient.<init>(HttpClient.java:159)
        at weblogic.net.http.HttpClient.<init>(HttpClient.java:149)
        at weblogic.net.http.HttpClient.New(HttpClient.java:265)
        at weblogic.net.http.HttpURLConnection.connect(HttpURLConnection.java:170)
        at com.bea.wsrp.util.CompatWsdlParser.getWsdlDocument(CompatWsdlParser.java:309)
        at com.bea.wsrp.util.CompatWsdlParser.getWsrpPortUrls(CompatWsdlParser.java:64)
        at com.bea.wsrp.wsdl.FixupWsdlParser.tryFixup(FixupWsdlParser.java:74)
        at com.bea.wsrp.wsdl.FixupWsdlParser.parse(FixupWsdlParser.java:63)
        at com.bea.wsrp.wsdl.WsdlInfoImpl.<init>(WsdlInfoImpl.java:169)
        at com.bea.wsrp.wsdl.GlobalWsdlPool.getWsdlInfo(GlobalWsdlPool.java:55)
        at com.bea.wsrp.consumer.resource.DefaultResourceConnectionFilter.getMarkupPortUrl(DefaultResourceConnectionFilter.java:79)
        at com.bea.wsrp.consumer.resource.DefaultResourceConnectionFilter.allowedURL(DefaultResourceConnectionFilter.java:37)
        at com.bea.wsrp.consumer.resource.ResourceProxyServlet.internalService(ResourceProxyServlet.java:219)
        at com.bea.wsrp.consumer.resource.ResourceProxyServlet.doGet(ResourceProxyServlet.java:157)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
        at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:226)
        at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:124)
        at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:283)
        at weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:26)
        at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:42)
        at com.bea.portal.tools.servlet.http.HttpContextFilter.doFilter(HttpContextFilter.java:60)
        at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:42)
        at com.bea.p13n.servlets.PortalServletFilter.doFilter(PortalServletFilter.java:315)
        at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:42)
        at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3368)
        at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
        at weblogic.security.service.SecurityManager.runAs(Unknown Source)
        at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2117)
        at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2023)
        at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1359)
        at weblogic.work.ExecuteThread.execute(ExecuteThread.java:200)
        at weblogic.work.ExecuteThread.run(ExecuteThread.java:172)

Looking at the stack trace above, the issue appeared to be a connection hanging when the DefaultResourceConnectionFilter tried to get the WSDL from a producer. The obvious question was why was this class attempting to get a producer WSDL? Using JAD, a Java decompiler, along with Jadclipse it was easy to see what was happening by looking at the code.

In WLP 8.1, a connection filter was the primary way to secure the ResourceProxyServlet to ensure that it only accessed specific content. Otherwise the proxy servlet becomes a security hole since it could be used to access arbitrary resources from any machine the consumer had access to simply by manipulating the wsrp-url parameter in the resource request. You can view the original 8.1 documentation at Creating a Resource Connection Filter. In WLP 10 this feature is still available but somewhat deprecated in favor of the WebLogic Server connection filter.

Having said that, a default connection filter is still used with the resource proxy servlet and what it does is to ensure that the requested resource IP address matches an IP address for one of the producers markup address. This was where the WSDL request was coming from, the filter needs the markup address from the WSDL to do this comparison. The problem the client had was that the application's wsrp-producer-registry.xml had a dead producer in it, while none of the proxy portlets referenced it the default connection filter still used it to check resource requests. When it tried to get the WSDL for the dead producer the connection hung until a TCP timeout occurred since the IP referenced was not available on the test network.

So now that issue was out of the way, the client tried accessing the resource again and was finding that the resource request returned immediately but with a 401-Forbidden status code. Looking at the logs again we saw the following error being logged on the producer:

<Mar x, 2008 x:xx:xx PM EST> <Warning> <WSRP-Consumer> <BEA-420756> <[/xxxxxx] Resource http://xxx.xxx.xxx.xxx:xxxxx/xxxxx/javascript/xxxxxxxx.js requested by client from xxx.xxx.xxx.xxx not served.>

This is a message returned by the DefaultResourceConnectionFilter when it refuses to serve a request. Looking at the IP requested it matched the IP registered for the producer's WSDL so it was not immediately obvious what the issue was. However after looking at the code for the DefaultResourceConnectionFilter class, it showed that it was using the markup address and not the WSDL address for doing the comparison. When you access a producer WSDL you will see that it contains a variety of IP addresses in bindings for getting the markup, the service description and others which are created by the producer. These addresses are the ones actually used by the underlying WSRP implementation to interact with the remote portlet, not the WSDL address.

The customer had a clustered environment for the producer but did not have the front-end host parameters set, thus these bindings contained the IP and port of a server in the cluster rather then the appliance that was fronting the cluster. As a result the address for the resource, which was the front end appliance, did not match the server's address. The solution here was an easy one, setting the front-end host parameters for the producer cluster in the WebLogic console corrected the issue in that the generated WSDL service addresses now used the front end host settings. As a result the resource started being served correctly.

So there you have it, a few interesting tidbits learned about the ResourceProxyServlet.



Evil Overlord 101

Posted by gnunn on January 21, 2008 at 6:50 AM | Permalink | Comments (1)

And now for something completely different. My son got me a game for the Xbox 360 called Overlord, the game puts the fantasy genre on its head by putting you in the role of the evil Overlord leading your army of minions to world domination. Overall a fun game that fulfills a long standing ambition of mine that my wife is continually, and successfully, thwarting. I was searching for some tips for this game when I stumbled across this site, How To Be A Successful Evil Overlord. However instead of tips for the game, it has 100 tips on avoiding the classic blunders an evil Overlord can make.

As a software developer or member of an IT staff you never know what sort of project you will be undertaking so I've extracted the IT related tips for those of you who might end up working for Hank Scorpio.

50. My main computers will have their own special operating system that will be completely incompatible with standard IBM and Macintosh powerbooks.

59. I will never build a sentient computer smarter than I am.

60. My five-year-old child advisor will also be asked to decipher any code I am thinking of using. If he breaks the code in under 30 seconds, it will not be used. Note: This also applies to passwords.

65. If I must have a computer system with publicly available terminals, the maps they display will have a room clearly marked as the Main Control Room. That room will be the Execution Chamber. The actual main control room will be marked as Sewage Overflow Containment.

74. When I create a multimedia presentation of my plan designed so that my five-year-old advisor can easily understand the details, I will not label the disk "Project Overlord" and leave it lying on top of my desk.

99. Any data files of crucial importance will be padded to 1.45Mb.

100. Finally, to keep my subjects permanently locked in a mindless trance, I will provide each of them with free, unlimited internet access.

I would recommend reading the full list if you are thinking of making a career change from software developer to evil Overlord to avoid the mistakes of your predecessors. I particularly enjoyed this non-IT related one:

81. If I am fighting with the hero atop a moving platform, have disarmed him, and am about to finish him off and he glances behind me and drops flat, I too will drop flat instead of quizzically turning around to find out what he saw.



Delivering Data from Portal Events to Page Flows

Posted by gnunn on January 11, 2008 at 3:41 PM | Permalink | Comments (2)

If you are working on a portlet project you likely will be familiar with inter-portlet communication (IPC) and Java Page Flows (JPFs). When creating IPC events, one option that is available is to invoke a JPF action in response to the event. One question that often arises though is how do you deliver data to that action?

For example, let's say you have an e-commerce portal and you have a portlet that displays an individual product. This portlet has an event that can be invoked by other portlets to display a selected product and the event that is fired contains a payload that holds the product name. So now the JPF action that is being invoked needs to get that product name in order to process it. A traditional way of doing this is to have a backing file unpack the payload and store it in the request or session where it can be retrieved by the JPF action. I've done it this way myself many times, but Nathan Lipke, one of our Portal engineers, pointed out an alternative way to handle this scenario.

It is not well documented, but if the event payload object extends the org.apache.struts.action.ActionForm object it can be delivered directly to the JPF action method without requiring the use of an intermediate backing file. Let's look at an example to make this clearer.

Using our previous example of selecting a product, here is a payload object that we define to allow one portlet to pass the selected product to another object.

public class ProductBean extends ActionForm implements Serializable {

    private String product;

    public ProductBean() {

    }

    public ProductBean(String product) {
        this.product = product;
    }

    public String getProduct() {
        return product;
    }

    public void setProduct(String product) {
        this.product = product;
    }

    @Override
    public String toString() {
        return super.toString()+"["+product+"]";
    }
}

Now we need to define an action in the JPF in our portlet to be notified when the event is fired as follows.

@Jpf.Action(forwards = { @Jpf.Forward(name = "success", path = "product.jsp") })
public Forward displayProduct(ProductBean bean) {
    this.product = bean.getProduct();
    return new Forward("success");
}

In the portlet itself, create an event handler as normal and add the invoke page flow action to the handler specifying the displayProduct action we created previously. Here is an example of how the XML would look in the .portlet file.

<netuix:handleCustomEvent event="displayProductEvent"
	eventLabel="handleDisplayProductEvent" fromSelfInstanceOnly="false"
	onlyIfDisplayed="false">
	<netuix:invokePageFlowAction action="displayProduct" />
</netuix:handleCustomEvent>

Finally in the other portlet we need to fire the event using the PortletBackingContext as follows:

PortletBackingContext pbc = PortletBackingContext.getPortletBackingContext(getRequest());
pbc.fireCustomEvent("displayProductEvent", new ProductBean(selectedProduct));

That's basically it, as mentioned previously the key to making this work is having the event payload extend the ActionForm object. Thanks again to Nathan Lipke for pointing this out to me.



Portlet Render Dependencies and CSS Image References

Posted by gnunn on December 14, 2007 at 9:34 AM | Permalink | Comments (1)

As some of you may know, WebLogic Portal enables a portlet to declare a dependency on CSS and JS files independent of the Portal, this feature is called render dependencies and is documented here http://edocs.bea.com/wlp/docs100/portlets/building.html#wp1073505.

This feature can be handy in a WSRP situation where a portlet may have a dependency on specific CSS that is unavailable to the consumer. In a WSRP scenario, the link to the CSS file is rewritten so that it is streamed to the browser from the producer using the consumer's ResourceProxyServlet. I won't spend time on ResourceProxyServlet as I've blogged about this previously at http://dev2dev.bea.com/blog/gnunn/archive/2006/03/wsrp_and_remote.html so see that article for more info on this feature if you need it.

One of the issues with this feature though is that CSS is often dependent on images, in fact in this Web 2.0 world it is pretty rare to find a CSS file that doesn't contain image references. The problem we encounter with this in WSRP is that while the referenced images in the CSS exist on the producer the resolving of the image reference is done by the browser. For example, assume the following portlet CSS:

.test {
    background-image: url('/portlets/test/css/blue.jpg')
}

When this CSS is passed to the browser, the browser will in turn connect to the consumer and attempt to download blue.jpg relative to the location of the CSS. However because the CSS was served by the consumer's ResourceProxyServlet, this reference will not work because the image is not located on the consumer and the browser will fail to resolve the image.

One option would be to hard code the reference for the consumer's ResourceProxyServlet in the producer's portlet CSS but this would be a poor solution indeed since we would be tightly coupling the producer CSS to the consumer. I was researching this further and when I looked over the render dependency documentation referenced above, there is a section called Rewriting Resource URLs that describes rewriting resource references so that they can be successfully streamed from the producer using the consumer's ResourceProxyServlet.

Thinking that this looked interesting I resolved to test it out. I created a small portlet and a CSS file that appears as follows as per the documentation.

.test {
    background-image: url('wlp_rewrite?/portlets/test/css/blue.jpg/wlp_rewrite')
}

Next I created a render dependency file as follows and linked it to the portlet. Here is the render dependency file called test.dependencies:

<?xml version="1.0" encoding="UTF-8"?>
<p:window xmlns:p="http://www.bea.com/servers/portal/framework/laf/1.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.bea.com/servers/portal/framework/laf/1.0.0 laf-window-1_0_0.xsd ">
    <p:render-dependencies>
        <p:html>
            <p:links>
                <p:search-path>
                    <p:path-element>css</p:path-element>
                </p:search-path>
                <p:link rel="stylesheet" type="text/css" href="test.css" />
            </p:links>
        </p:html>
    </p:render-dependencies>
</p:window>

I then linked this file to the portlet in question and gave it a try in a test application. There is a great tool called FireBug for FireFox that enables you to easily inspect CSS. Using this tool I was quite disappointed to see that the image reference in the CSS was not being rewritten.

At this point I was a bit stumped and made an inquiry on our internal Portal support mailing list. After some interesting discussions George Murnock, one of our Portal engineers, gave me the low down on what I was doing wrong. This feature only works if the CSS is inlined so that the Portal rewriters are used when writing the content to the response. To inline the CSS instead of referencing the content I needed to make some small tweaks to my dependency file as follows:

<?xml version="1.0" encoding="UTF-8"?>
<p:window xmlns:p="http://www.bea.com/servers/portal/framework/laf/1.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.bea.com/servers/portal/framework/laf/1.0.0 laf-window-1_0_0.xsd ">
    <p:render-dependencies>
        <p:html>
            <p:styles>
                <p:search-path>
                    <p:path-element>css</p:path-element>
                </p:search-path>
                 <p:style type="text/css" content-uri="test.css" />
            </p:styles>
        </p:html>
    </p:render-dependencies>
</p:window>

This causes the CSS file to be inlined with the HTML and thus Portal's rewriter will modify the URLs as needed. With this change the CSS above then becomes the following:

.test {
    background-image: url('http://localhost:7001/consumer/resource?_windowLabel=ptlEventTest_2_1&wsrp-urlType=resource&wsrp-url=http%3A%2F%2Flocalhost%3A7001%2Fproducer%2Fportlets%2Ftest%2Fcss%2Fblue.jpg&wsrp-requiresRewrite=true&');
}

One minor annoyance with this technique is that it requires the CSS to be inlined in the HTML rather then delivered as a separate CSS file. The issue with this is that the CSS will not be cached by the browser. This somewhat mitigated by the fact that the content is rewritten only once at the WebLogic layer and then cached, however for large CSS files George suggested splitting the elements that need rewriting into separate and smaller CSS files to mitigate this further.

Thanks again to George Murnock for helping me out with this.



When in Rome...

Posted by gnunn on August 8, 2007 at 12:08 PM | Permalink | Comments (1)

The old expression "When in Rome do as the Romans do" applies to development as well. One thing I always try to encourage developers to do when building an application is to try to make their development environment as similar as possible to the production environment. Now obviously this isn't practical in all cases, if you are deploying to Solaris you probably don't want to foist Solaris on all your developers. Similarly it's not practical from a performance point of view to develop against a local clustered environment.

Having said that, when building a portlets that are intended to be used in a federated environment it is a good practice for developers to run and test these portlets as remote rather then local portlets in their development environments. When building a portlet, the tendency is to simply drop the local portlet onto a test portal in order to test the portlet's functionality. The problem with this approach is that there may be issues that only appear when the portlet is deployed in a federated environment, for example the developer relying on the same request object to be used throughout the portlet's lifecycle. These kind of issues can be caught and corrected early by simply testing the portlet as a remote portlet from the get go.

There is not much excuse not to do this as testing remote portlets is quite simple and convenient, instead of just dropping the local portlet on your test portal, create a new remote portlet whose WSDL points to the local instance of WLP that is running. Essentially everything is still running on the same WLP instance, however the portlet is running as a remote portlet allowing you to ensure that everything will work as expected in a federated environment.



Discover your inner Simpson

Posted by gnunn on August 8, 2007 at 11:47 AM | Permalink | Comments (2)

A non-technical post for a change of pace even though we aren't supposed to blog about this sort of thing, Jon our editor wields his editorial power with an iron fist (albeit while holding a donut), but there is something about the Simpsons that appeals to technical folks everywhere.

One of my favorite episodes (and hey Jon this is computer related at least!) is when Homer puts on a few pounds to be obese so he can stop going to work because he's disabled. They install a computer at his home which of course he knows nothing about, the best moment from the episode being:

Homer (reading from PC screen): "To start press any key"; where's the any key? Is see esk (ESC), keturl (CTRL) and pigup (PgUp) but there doesn't seem to be any any key... Phew, all this computer hacking is making me thirsty, I think I'll order a tab. *presses TAB key, whilst holding up cup to CD Drive... Computer springs to life*

Anyways, in conjunction with the movie there is a site at www.simpsonizeme.com where you can upload a photograph of yourself and they send you back an e-mail with a simpsonized version of you. Here is my inner Simpson, quite the dapper fellow I must say.

Jon, can I use this as my dev2dev blog photo?



More on ResourceProxyServlet in WSRP

Posted by gnunn on June 25, 2007 at 4:08 PM | Permalink | Comments (0)

An earlier blog post I wrote, WSRP and Remote Resources, talked about how to use the ResourceProxyServlet to serve resources such as images and css from the producer to the browser by using the consumer as a proxy. This is often necessary because the producer is behind a firewall and the browser cannot access resources on the producer directly.

One feature of the ResourceProxyServlet is that it also proxies response headers from the producer to the end user's browser. This is a nice feature because resources often have headers associated with them that control caching and expiration. Unfortunately, the set-cookie header can also be copied to the browser and if the consumer and producer share the same cookie name and path this can result in the producer cookie overwriting the consumer cookie causing a loss of session on the consumer.

This issue is well documented in the Federated Portals Guide under the Configuring Session Cookies section. The documentation available here presents two potential solutions to the problem, one involving changing the cookie name or path and the other blocking the proxying of all response headers.

I was recently assisting a client on WLP 10 who was experiencing this issue and neither of the above two options were particularly optimal for their situation. The client had existing infrastructure that relied on the JSESSIONID cookie name that would need to be re-configured if this was changed. The second solution would prevent the client from controlling some headers that they may want to tune in the future.

Fortunately, a new feature has been added in WLP 10 that provides a better solution then either of the two currently documented. In the file wsrp-producer-registry.xml, a new stanza has been added called resource-cookies. This allows developers to configure whether or not producers can set cookies when resources are requested through the ResourceProxyServlet. By default, this is set to block-none which allows the producer to set cookies as needed, by changing this to block-all the set-cookie header is no longer proxied from the producer thereby preventing the session issue in a much cleaner way then the current alternatives.

This feature should be documented on edocs in the near future. I would like to thank Subbu Allamaraju for his detailed explanation of this feature when I stumbled across it.



Maven 2 and Portal: Article Addendum

Posted by gnunn on May 31, 2007 at 6:55 PM | Permalink | Comments (7)

Continue Reading...



Maven 2 and Checkstyle

Posted by gnunn on May 23, 2007 at 6:48 AM | Permalink | Comments (0)

I recently wrote an article about integrating Maven 2 with WebLogic Portal and I found working with Maven an interesting experience. One excellent feature of Maven 2 that I am extensively using is the ability to generate a web site for the project automatically. This web site can include a variety of generated reports including project information and documentation, the results of your unit tests, javadoc and more.

One of the available reports in Maven is a Checkstyle report, I wanted to leverage it in order to ensure compliance with the organization's coding standards. If you are not familiar with Checkstyle, it parses your source code and provides a report with regards to how compliant the code is with a given convention. Additional information on Checkstyle can be found at http://checkstyle.sourceforge.net.

Checkstyle ships with a few default conventions including the Sun coding standards, however most organizations customize this and create their own configuration. The question arises though as to how to centralize this configuration so that it does not need to be manually configured when a project build is done.

Fortunately, this issue is easily addressed using the built-in dependency mechanism in Maven. Essentially we simply bundle the Checkstyle xml configuration file into a JAR and then install this into a Maven repository, typically this will be an organization's internal intranet repository. When the project site is built, this configuration is automatically fetched from the repository and applied when needed.

Configuring this is straightforward, first in the project pom.xml we define the dependency on the checkstyle configuration JAR as an extension dependency, this can be done as follows:


<build>
    <extensions>
        <extension>
            <groupId>com.bea.ps</groupId>
            <artifactId>checkstyle-config</artifactId>
            <version>1.0.0</version>
        </extension>
    </extensions>
</build>

Next we reference the configuration file in the Checkstyle plug-in configuration in the reporting section. Note that the Checkstyle plugin will search the URL classpath for the resource before trying the file system, this is why storing the configuration file in a JAR works. The configLocation referenced below is where checks.xml is located on the classpath in the checkstyle-config.jar referenced above.


<reporting>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-checkstyle-plugin</artifactId>
            <configuration>
              <configLocation>config/checks.xml</configLocation>
            </configuration>
        </plugin>
    </plugins>
</reporting>

That should be it, now the configuration can be centrally managed and controlled and projects can get the latest version simply by updating the version of the artifact in the extension section.



Handling Global Parameters and Events in WLP 9.2

Posted by gnunn on February 19, 2007 at 6:24 AM | Permalink | Comments (2)

Inter-portlet communication (IPC) is a powerful technique for exchanging messages between portlets in a loosely coupled fashion, it allows portlets to work together with no knowledge of where each other is located in the Portal structure. However like most things, except for maybe Chuck Norris, it does have one achille's heel and that is the fact that only portlets can send and receive IPC events.

This issue becomes evident on larger portal projects when you may find quite a few instances where you would like to be able to send or receive an event on a global basis. As an example, when certain parameters are posted to the portal from an external web site you may want to send an event to initiate an action. Or maybe you want to have an event handled at a global level since it affects the portal itself rather then an individual portlet.

A common technique for doing this is to simply place a dummy portlet on a non-visible page. This works well with respect to sending and receiving events, but will not work if you want to send an event in response to posted parameters unless you force the hidden page to be active. Additionally, another weakness with this technique is that with streaming portals it is possible for an administrator to accidentally remove the portlet without understanding what it is doing.

An alternative technique that I prefer is to create a controller portlet that is embedded in the shell. Embedding the portlet in the shell ensures that the portlet will participate in every request and always be present. Additionally, the administrator can only remove the portlet by changing the shell which is not likely to happen and can be avoided by embedding the portlet in all available shells.

Embedding the portlet in the shell is straightforward, simply open the target .shell file and then use the netuix:portletInstance element to embed the portlet within the netuix:header element. Here is an example:

<netuix:header>
    <netuix:portletInstance 
        instanceLabel="_eventController" 
        markupType="Portlet"     
        contentUri="/portlets/controller/controller.portlet"/>
</netuix:header>

Another thing I have been exploring is to combine this technique with Spring to register backing file services for use with the controller portlet. Instead of having one large backing file that handles everything, I have many small service classes that are injected into the backing file of the controller portlet. I’ll post more about this later.



Creating a Print Optimized Portal in WLP 9.2

Posted by gnunn on February 15, 2007 at 8:02 AM | Permalink | Comments (4)

A common business requirement for portals is that they have an optimized version for printing. Typically a print optimized version means that when a user goes to print the portal it should print without superfluous elements like the header, footer, left navigation, etc. Additionally some formatting elements may change to better suit the printed page.

In most standard websites this is typically done by using Cascading Style Sheets (CSS). As most of you know, CSS controls how various elements look on the screen in terms of their color, font, etc. CSS has the notion of a media type that determines which CSS is used for which media. Common media types include screen and print and a full list is available here http://www.w3.org/TR/REC-CSS2/media.html.

Browsers will automatically take advantage of the media type when specified. Thus when printing a page that has print CSS files specified, the browser will automatically incorporate those styles when printing. This gives the developer a lot of control over how the content is rendered for printing purposes and eliminates having to hit the server again to retrieve a page formatted for printing.

Also, keep in mind that CSS can also be used to determine if elements are displayed or hidden as well and it is this capability that we can leverage to create a print version of our portal. Using the display style in CSS you can easily turn off the header, footer, left navigation and other elements that you do not want to appear in the printed page.

Fortunately for us WLP is heavily based on CSS and we can use the same mechanism within a portal. The file skin.xml controls what CSS files are used as part of the CSS and skin.xml fully supports the media attribute in WLP 9.2. By creating an additional print.css stylesheet we can easily turn off the display of headers and footers when the page is printed. Alternatively, for more complex requirements you could also have a parallel set of stylesheets specifically tuned for the print media type.

As an example, here is a reduced screenshot of a sample web site I have as part of a dev2dev codeshare project I am working on.

avitek_default.jpg

To remove the header and footer when printed, I created a stylesheet called print.css which contains the following css:

.bea-portal-body-header, .bea-portal-body-footer {
	display: none;
}

Next I added my new stylesheet to the skin.xml that resides in the skin directory of my look and feel. The skin.xml file is a new feature that provides the developer with fine grained control over the skin definition, it replaces the skin.properties file that was used in 8.1. Adding our new stylesheet to the list of dependencies is trivial and the new line appears as follows:

<ns:link href="css/print.css" 
               rel="stylesheet" 
               type="text/css" 
               media="print"/>

Now that we have this new stylesheet in place, if we open Firefox and do a print preview we can see that the header and footer have now disappeared when printing.

avitek_print.gif


May 2008

Sun Mon Tue Wed Thu Fri Sat
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31


Search this blog:


Archives

May 2008
April 2008
March 2008
January 2008
December 2007
August 2007
June 2007
May 2007
February 2007
July 2006
March 2006
February 2006
August 2005
June 2005
April 2005

Categories

Version Information and BEA Workshop blogs for more details. ">Product: BEA Workshop Product Family
Product: WebLogic Portal
Product: WebLogic Server
Technology: Dev Toolbox

Recent Entries

Blog Moving Day

Best Practices for Links in WebLogic Portal

WebLogic Portal Analytics API

Articles

Using Maven 2 to Build WebLogic Portal Applications
Apache Maven 2 is a popular open-source build system. In this tutorial, Gerald Nunn shows how to use Maven 2 to build WebLogic Portal applications. Mar. 7, 2007

Portal Menus and Windowed Controls
Gerald Nunn shows you how to use a simple IFRAME shim technique to solve the problem in WebLogic Portal of HTML elements being hidden by other DHTML elements when the page is rendered with Internet Explorer. Apr. 5, 2005

Paging and Sorting using the netui:repeater tag
Find out how to implement an efficient and reusable paging and sorting system for displaying data using the netui:repeater tag in BEA WebLogic Workshop 8.1. Feb. 7, 2005

All articles by Gerald Nunn »


Powered by
Movable Type 3.31