December 2007
« January 2008 | Main | August 2007 »Portlet Render Dependencies and CSS Image References
Friday, December 14, 2007
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://www.gexperts.com/blog/archives/03-01-2006_03-31-2006.html#9 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.
Posted by Gerald Nunn at 4:01 PM | Categories: WebLogic | | | Permalink
