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.
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.
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.
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.
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:
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.
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.
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.
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.
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.
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
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:
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.
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:
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:
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.
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.
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*
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.
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:
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.
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.
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:
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.
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.
To remove the header and footer when printed, I created a stylesheet called print.css which contains the following css:
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:
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.
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