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
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