How to avoid the Portlet Skin mismatch
Posted
by Martin Deh
on Oracle Blogs
See other posts from Oracle Blogs
or by Martin Deh
Published on Tue, 19 Jun 2012 15:33:18 +0000
Indexed on
2012/06/19
21:21 UTC
Read the original article
Hit count: 986
/WebCenter/WebCenter Portal
here are probably many on going debates whether to use portlets or taskflows in a WebCenter custom portal application. Usually the main battle on which side to take in these debates are centered around which technology enables better performance. The good news is that both of my colleagues, Maiko Rocha and George Maggessy have posted their respective views on this topic so I will not have to further the discussion. However, if you do plan to use portlets in a WebCenter custom portal application, this post will help you not have the "portlet skin mismatch" issue. An example of the presence of the mismatch can be view from the applications log:
The skin customsharedskin.desktop specified on the requestMap will be used even though the consumer's skin's styleSheetDocumentId on the requestMap does not match the local skin's styleSheetDocument's id. This will impact performance since the consumer and producer stylesheets cannot be shared. The producer styleclasses will not be compressed to avoid conflicts. A reason the ids do not match may be the jars are not identical on the producer and the consumer. For example, one might have trinidad-skins.xml's skin-additions in a jar file on the class path that the other does not have.
Notice that due to the mismatch the portlet's CSS will not be able to be compressed, which will most like impact performance in the portlet's consuming portal. The first part of the blog will define the portlet mismatch and cover some debugging tips that can help you solve the portlet mismatch issue. Following that I will give a complete example of the creating, using and sharing a shared skin in both a portlet producer and the consumer application.
Portlet Mismatch Defined
In general, when you consume/render an ADF page (or task flow) using the ADF Portlet bridge, the portlet (producer) would try to use the skin of the consumer page - this is called skin-sharing. When the producer cannot match the consumer skin, the portlet would generate its own stylesheet and reference it from its markup - this is called mismatched-skin. This can happen because:
- The consumer and producer use different versions of ADF Faces, or
- The consumer has additional skin-additions that the producer doesn't have or vice-versa, or
- The producer does not have the consumer skin
For case (1) & (2) above, the producer still uses the consumer skin ID to render its markup. For case (3), the producer would default to using portlet skin.
If there is a skin mis-match then there may be a performance hit because:
- The browser needs to fetch this extra stylesheet (though it should be cached unless expires caching is turned off)
- The generated portlet markup uses uncompressed styles resulting in a larger markup
It is often not obvious when a skin mismatch occurs, unless you look for either of these indicators:
- The log messages in the producer log, for example:
The skin blafplus-rich.desktop specified on the requestMap will not be used because the styleSheetDocument id on the requestMap does not match the local skin's styleSheetDocument's id. It could mean the jars are not identical. For example, one might have trinidad-skins.xml's skin-additions in a jar file on the class path that the other does not have.
- View the portlet markup inside the iframe, there should be a <link> tag to the portlet stylesheet resource like this (note the CSS is proxied through consumer's resourceproxy):
<link rel=\"stylesheet\" charset=\"UTF-8\" type=\"text/css\" href=\"http:.../resourceproxy/portletId...252525252Fadf%252525252Fstyles%252525252Fcache%252525252Fblafplus-rich-portlet-d1062g-en-ltr-gecko.css...
Using HTTP monitoring tool (eg, firebug, httpwatch), you can see a request is made to the portlet stylesheet resource (see URL above)
There are a number of reasons for mismatched-skin. For skin to match the producer and consumer must match the following configurations:
- The ADF Faces version (different versions may have different style selectors)
- Style Compression, this is defined in the web.xml (default value is false, i.e. compression is ON)
- Tonal styles or themes, also defined in the web.xml via context-params
- The same skin additions (jars with skin) are available for both producer and consumer. Skin additions are defined in the trinidad-skins.xml, using the <skin-addition> tags. These are then aggregated from all the jar files in the classpath. If there's any jar that exists on the producer but not the consumer, or vice veras, you get a mismatch.
Debugging Tips
- Ensure the style compression and tonal styles/themes match on the consumer and producer, by looking at the web.xml documents for the consumer & producer applications
- It is bit more involved to determine if the jars match. However, you can enable the Trinidad logging to show which skin-addition it is processing. To enable this feature, update the logging.xml log level of both the producer and consumer WLS to FINEST. For example, in the case of the WebLogic server used by JDeveloper:
$JDEV_USER_DIR/system<version number>/DefaultDomain/config/fmwconfig/servers/DefaultServer/logging.xml
Add a new entry:
<logger name="org.apache.myfaces.trinidadinternal.skin.SkinUtils" level="FINEST"/>
- Restart WebLogic. Run the consumer page, you should see the following logging in both the consumer and producer log files. Any entries that don't match is the cause of the mismatch. The following is an example of what the log will produce with this setting:
[SRC_CLASS: org.apache.myfaces.trinidadinternal.skin.SkinUtils] [APP: WebCenter] [SRC_METHOD: _getMetaInfSkinsNodeList] Processing skin URL:zip:/tmp/_WL_user/oracle.webcenter.skin/in1ar8/APP-INF/lib/announcement-skin.jar!/META-INF/trinidad-skins.xml Processing skin URL:zip:/tmp/_WL_user/oracle.webcenter.skin/in1ar8/APP-INF/lib/calendar-skin.jar!/META-INF/trinidad-skins.xml Processing skin URL:zip:/tmp/_WL_user/oracle.webcenter.skin/in1ar8/APP-INF/lib/custComps-skin.jar!/META-INF/trinidad-skins.xml Processing skin URL:zip:/tmp/_WL_user/oracle.webcenter.skin/in1ar8/APP-INF/lib/forum-skin.jar!/META-INF/trinidad-skins.xml Processing skin URL:zip:/tmp/_WL_user/oracle.webcenter.skin/in1ar8/APP-INF/lib/page-service-skin.jar!/META-INF/trinidad-skins.xml Processing skin URL:zip:/tmp/_WL_user/oracle.webcenter.skin/in1ar8/APP-INF/lib/peopleconnections-kudos-skin.jar!/META-INF/trinidad-skins.xml Processing skin URL:zip:/tmp/_WL_user/oracle.webcenter.skin/in1ar8/APP-INF/lib/peopleconnections-wall-skin.jar!/META-INF/trinidad-skins.xml Processing skin URL:zip:/tmp/_WL_user/oracle.webcenter.skin/in1ar8/APP-INF/lib/portlet-client-adf-skin.jar!/META-INF/trinidad-skins.xml Processing skin URL:zip:/tmp/_WL_user/oracle.webcenter.skin/in1ar8/APP-INF/lib/rtc-skin.jar!/META-INF/trinidad-skins.xml Processing skin URL:zip:/tmp/_WL_user/oracle.webcenter.skin/in1ar8/APP-INF/lib/serviceframework-skin.jar!/META-INF/trinidad-skins.xml Processing skin URL:zip:/tmp/_WL_user/oracle.webcenter.skin/in1ar8/APP-INF/lib/smarttag-skin.jar!/META-INF/trinidad-skins.xml Processing skin URL:zip:/tmp/_WL_user/oracle.webcenter.skin/in1ar8/APP-INF/lib/spaces-service-skins.jar!/META-INF/trinidad-skins.xml Processing skin URL:zip:/tmp/_WL_user/oracle.webcenter.composer/3yo7j/WEB-INF/lib/custComps-skin.jar!/META-INF/trinidad-skins.xml Processing skin URL:zip:/tmp/_WL_user/adf.oracle.domain.webapp/q433f9/WEB-INF/lib/adf-richclient-impl-11.jar!/META-INF/trinidad-skins.xml Processing skin URL:zip:/tmp/_WL_user/adf.oracle.domain.webapp/q433f9/WEB-INF/lib/dvt-faces.jar!/META-INF/trinidad-skins.xml Processing skin URL:zip:/tmp/_WL_user/adf.oracle.domain.webapp/q433f9/WEB-INF/lib/dvt-trinidad.jar!/META-INF/trinidad-skins.xml
The Complete Example
The first step is to create the shared library. The WebCenter documentation covering this is located here in section 15.7. In addition, our ADF guru Frank Nimphius also covers this in hes blog. Here are my steps (in JDeveloper) to create the skin that will be used as the shared library for both the portlet producer and consumer.
- Create a new Generic Application
- Give application name (i.e. MySharedSkin)
- Give a project name (i.e. MySkinProject)
- Leave Project Technologies blank (none selected), and click Finish
- Create the trinidad-skins.xml
- Right-click on the MySkinProject node in the Application Navigator and select "New"
- In the New Galley, click on "General", select "File" from the Items, and click OK
- In the Create File dialog, name the file trinidad-skins.xml, and (IMPORTANT) give the directory path to MySkinProject\src\META-INF
- In the trinidad-skins.xml, complete the skin entry. for example:
<?xml version="1.0" encoding="windows-1252" ?>
<skins xmlns="http://myfaces.apache.org/trinidad/skin">
<skin>
<id>mysharedskin.desktop</id>
<family>mysharedskin</family>
<extends>fusionFx-v1.desktop</extends>
<style-sheet-name>css/mysharedskin.css</style-sheet-name>
</skin>
</skins>
- Create CSS file
- In the Application Navigator, right click on the META-INF folder (where the trinidad-skins.xml is located), and select "New"
- In the New Gallery, select Web-Tier-> HTML, CSS File from the the Items and click OK
- In the Create Cascading Style Sheet dialog, give the name (i.e. mysharedskin.css)
- Ensure that the Directory path is the under the META-INF (i.e. MySkinProject\src\META-INF\css)
- Once the new CSS opens in the editor, add in a style selector. For example, this selector will style the background of a particular panelGroupLayout:
af|panelGroupLayout.customPGL{
background-color:Fuchsia;
}
- Create the MANIFEST.MF (used for deployment JAR)
- In the Application Navigator, right click on the META-INF folder (where the trinidad-skins.xml is located), and select "New"
- In the New Galley, click on "General", select "File" from the Items, and click OK
- In the Create File dialog, name the file MANIFEST.MF, and (IMPORTANT) ensure that the directory path is to MySkinProject\src\META-INF
- Complete the MANIFEST.MF, where the extension name is the shared library name
Manifest-Version: 1.1
Created-By: Martin Deh
Implementation-Title: mysharedskin
Extension-Name: mysharedskin.lib.def
Specification-Version: 1.0.1
Implementation-Version: 1.0.1
Implementation-Vendor: MartinDeh
- Create new Deployment Profile
- Right click on the MySkinProject node, and select New
- From the New Gallery, select General->Deployment Profiles, Shared Library JAR File from Items, and click OK
- In the Create Deployment Profile dialog, give name (i.e.mysharedskinlib) and click OK
- In the Edit JAR Deployment dialog, un-check Include Manifest File option
- Select Project Output->Contributors, and check Project Source Path
- Select Project Output->Filters, ensure that all items under the META-INF folder are selected
- Click OK to exit the Project Properties dialog
- Deploy the shared lib to WebLogic (start server before steps)
- Right click on MySkin Project and select Deploy
- For this example, I will deploy to JDeverloper WLS
- In the Deploy dialog, select Deploy to Weblogic Application Server and click Next
- Choose IntegratedWebLogicServer and click Next
- Select Deploy to selected instances in the domain radio, select Default Server (note: server must be already started), and ensure Deploy as a shared Library radio is selected
- Click Finish
- Open the WebLogic console to see the deployed shared library
The following are the steps to create a simple test Portlet
- Create a new WebCenter Portal - Portlet Producer Application
- In the Create Portlet Producer dialog, select default settings and click Finish
- Right click on the Portlets node and select New
- IIn the New Gallery, select Web-Tier->Portlets, Standards-based Java Portlet (JSR 286) and click OK
- In the General Portlet information dialog, give portlet name (i.e. MyPortlet) and click Next 2 times, stopping at Step 3
- In the Content Types, select the "view" node, in the Implementation Method, select the Generate ADF-Faces JSPX radio and click Finish
- Once the portlet code is generated, open the view.jspx in the source editor
- Based on the simple CSS entry, which sets the background color of a panelGroupLayout, replace the <af:form/> tag with the example code
<af:form>
<af:panelGroupLayout id="pgl1" styleClass="customPGL">
<af:outputText value="background from shared lib skin" id="ot1"/>
</af:panelGroupLayout>
</af:form>
- Since this portlet is to use the shared library skin, in the generated trinidad-config.xml, remove both the skin-family tag and the skin-version tag
- In the Application Resources view, under Descriptors->META-INF, double-click to open the weblogic-application.xml
- Add a library reference to the shared skin library (note: the library-name must match the extension-name declared in the MANIFEST.MF):
<library-ref>
<library-name>mysharedskin.lib.def</library-name>
</library-ref>
- Notice that a reference to oracle.webcenter.skin exists. This is important if this portlet is going to be consumed by a WebCenter Portal application. If this tag is not present, the portlet skin mismatch will happen.
- Configure the portlet for deployment
- Create Portlet deployment WAR
- Right click on the Portlets node and select New
- In the New Gallery, select Deployment Profiles, WAR file from Items and click OK
- In the Create Deployment Profile dialog, give name (i.e. myportletwar), click OK
- Keep all of the defaults, however, remember the Context Root entry (i.e. MyPortlet4SharedLib-Portlets-context-root, this will be needed to obtain the producer WSDL URL)
- Click OK, then OK again to exit from the Properties dialog
- Since the weblogic-application.xml has to be included in the deployment, the portlet must be deployed as a WAR, within an EAR
- In the Application dropdown, select Deploy->New Deployment Profile...
- By default EAR File has been selected, click OK
- Give Deployment Profile (EAR) a name (i.e. MyPortletProducer) and click OK
- In the Properties dialog, select Application Assembly and ensure that the myportletwar is checked
- Keep all of the other defaults and click OK
- For this demo, un-check the Auto Generate ..., and all of the Security Deployment Options, click OK
- Save All
- In the Application dropdown, select Deploy->MyPortletProducer
- In the Deployment Action, select Deploy to Application Server, click Next
- Choose IntegratedWebLogicServer and click Next
- Select Deploy to selected instances in the domain radio, select Default Server (note: server must be already started), and ensure Deploy as a standalone Application radio is selected
- The select deployment type (identifying the deployment as a JSR 286 portlet) dialog appears. Keep default radio "Yes" selection and click OK
- Open the WebLogic console to see the deployed Portlet
- Create Portlet deployment WAR
The last step is to create the test portlet consuming application. This will be done using the OOTB WebCenter Portal - Framework Application.
- Create the Portlet Producer Connection
- In the JDeveloper Deployment log, copy the URL of the portlet deployment (i.e. http://localhost:7101/MyPortlet4SharedLib-Portlets-context-root
- Open a browser and paste in the URL. The Portlet information page should appear. Click on the WSRP v2 WSDL link
- Copy the URL from the browser (i.e. http://localhost:7101/MyPortlet4SharedLib-Portlets-context-root/portlets/wsrp2?WSDL)
- In the Application Resources view, right click on the Connections folder and select New Connection->WSRP Connection
- Give the producer a name or accept the default, click Next
- Enter (paste in) the WSDL URL, click Next
- If connection to Portlet is succesful, Step 3 (Specify Additional ...) should appear. Accept defaults and click Finish
- Add the portlet to a test page
- Open the home.jspx. Note in the visual editor, the orange dashed border, which identifies the panelCustomizable tag.
- From the Application Resources. select the MyPortlet portlet node, and drag and drop the node into the panelCustomizable section. A Confirm Portlet Type dialog appears, keep default ADF Rich Portlet and click OK
- Configure the portlet to use the shared skin library
- Open the weblogic-application.xml and add the library-ref entry (mysharedskin.lib.def) for the shared skin library. See create portlet example above for the steps
- Since by default, the custom portal using a managed bean to (dynamically) determine the skin family, the default trinidad-config.xml will need to be altered
- Open the trinidad-config.xml in the editor and replace the EL (preferenceBean) for the skin-family tag, with mysharedskin (this is the skin-family named defined in the trinidad-skins.xml)
- Remove the skin-version tag
- Right click on the index.html to test the application
Notice that the JDeveloper log view does not have any reporting of a skin mismatch. In addition, since I have configured the extra logging outlined in debugging section above, I can see the processed skin jar in both the producer and consumer logs:
<SkinUtils> <_getMetaInfSkinsNodeList> Processing skin URL:zip:/JDeveloper/system11.1.1.6.38.61.92/DefaultDomain/servers/DefaultServer/upload/mysharedskin.lib.def/[email protected]/app/mysharedskinlib.jar!/META-INF/trinidad-skins.xml
© Oracle Blogs or respective owner