Wednesday, February 24, 2010

Fine grained WebCenter customization using MDS

Recently a customer contacted me asking if it is possible to customize WebCenter Spaces or, more specifically, the Content Presenter Component. The requirement is to, according to some arbitrary condition, show the document title property from UCM instead of its file name – unfortunately the title property is not currently publicly exposed – I’ve create Enhancement Request #9392299 to make the propertyMap property accessible. For now I will show how you can customize a WebCenter library to add the user that last modified the file will to be shown along the file name.

This is a screenshot of the Document Library File Picker window. Only the filename is shown in the file picker dialog:

ContentPresenterFileBrowserFile1

At first one would think that this is way too fine grained to be customized, or you would have to actually modify the source code for the page to add your own customizations and running the risk of breaking the component/application in case it is patched/upgraded – or, file an enhancement request that could take a couple of releases to make its way into the product. But that’s not the case with WebCenter and MDS.

As you probably know already, Oracle ADF and MDS are the foundations for WebCenter, so the same customization that can be applied to your own custom applications can be applied to WebCenter Spaces or any of its components in the same way.

This is what you will need for this exercise:

Create a customization-enabled application

Fire up JDeveloper and create a new WebCenter Application:

WebCenterAppTemplate

Name it accordingly, and give it also a meaningful package name. Go through the rest of the Application wizard steps and finish it.

For this customization we don’t really need a Customization Class. If you want to use a Customization Class I suggest reading the How to Create a Custom SiteCC Tip Layer section of the Developer’s Guide and also check out this cue card.

Let’s enable customization in our application. Go to Application Resources > Descriptors > ADF META-INF :

ContentMDSAppRes

Double click adf-config.xml to open it in overview mode. Now click on the [+] button and type in “SiteCC” (without quotes!). Select the class and click OK:

SiteCC

We also need to enable seeded customizations. For this go to your ViewController project properties, select ADF View and select the Enable seeded customizations checkbox:

VCSeedCust

Next, we register the reserved WebCenter layer on on JDEV_HOME\jdev\CustomizationLayerValues.xml. This is the file that where all layers are registered. If you’re using a Customization Class then remember that the layer value in the class must match the value in this file. The WebCenter layer value is not surprisingly called “webcenter”:

   1: <cust-layers  xmlns="http://xmlns.oracle.com/mds/dt">



   2:   <cust-layer name="site" id-prefix="s">



   3:       <!-- Generated id-prefix would be "s1" and "s2" for values



   4:     "site1" and "site2".-->



   5:       <cust-layer-value value="site1" display-name="Site One" id-prefix="1" />



   6:       <cust-layer-value value="site2" display-name="Site Two" id-prefix="2" />



   7:       <!-- Generated id-prefix would be "s" for value "site"



   8:        since no prefix was specified on the value -->



   9:       <!-- ADF SiteCC always returns the value as "site" -->



  10:       <cust-layer-value value="site" display-name="Site"/>



  11:       <cust-layer-value value="webcenter" display-name="WebCenter"/>



  12:    </cust-layer>




Save the file and close it.



Customizing an ADF Library



Now we need to start JDeveloper in customization mode. Go to Tools > Preferences > Roles and select Customization Developer. JDeveloper will restart automagically. Good time to go grab a coffee or a snack. ;-)



After drinking your coffee and/or having your snack, check if the newly added customization layer has been added successfully. You should be able to see it from the Customization Context Panel. Expand the Value listbox and select the WebCenter option":



CustContext



Go to the Navigator Display Options (yes, there’s a name for that icon) and select Show Libraries:



ShowLibraries



Here I also recommend setting your Package Level and Web Content Level to “Unlimited” so you don’t have to journey into the center of Earth to find what you’re looking for.



Now you should see all the libraries that have been included by default to your ViewController project when it was created.



Hunting for that surreptitious JSPX or JSFF that we need to customize.



Just in case you don’t know the meaning of the word above, here it is. Hey, I’m not a native English speaker and I like to learn new words!



This is where things get really interesting. We now need to find the needle in the haystack. Currently there’s no documentation for the JSPXs/JSFFs inside WebCenter ADF Libraries, and I wouldn’t count for one coming out before the Universe collapses again into a singularity. Due to the sheer amount of files it would be a maintenance nightmare to keep them semantically and syntactically aligned with any external documentation – although I have some ideas myself on how you could do that using RDF (more on that later) . Anyway, that means that we will need to do some investigative work to find out where the file we need to customize is located



Start by locating the ADF Library that most probably has the file. Go to your ViewController project properties > Libraries and Classpath > Add Library and locate the WebCenter Document Library Service View :



AddLibDocLibView



Go back to your ViewController project and locate the library - it was most probably added at the bottom. Now relax, take a deep breath an expand the library node. Look for a package named oracle.webcenter.doclib.view.jsf.fragments . Within it you’ll find the docPickerView.jsff file. That’s our needle!



docPickerView



Now that we found the fragment let’s take a peek at its structure and pinpoint where we need to add our customization. By drilling down into the fragment structure we can see af:panelStrechtLayout (center) > af:switcher > f:facet(tree) > af:tree (nodeStamp) > af:panelGroupLayout > af:outputText :



StructPanePickView



The output text value property, #{item.name}, is the one that renders the filename. Now we need to add a new outputText that will show who last modified the file, but how do you know what properties you can use to populate the outputText value property?



This is the part where things get a bit tricky. There’s no public documentation on what’s being exposed by the item object. After some investigative work I could find that it exposes very few properties like mIMEType, (file)name, lastModifiedBy, lastModified,createDate, and contentType. This is not documented because they are exposed by an internal class called VCRMainViewItemBean. This class also has a boolean isFolder method that we’ll be using to render or not the new outputText we will add to the page. You can find other properties from the jsff page source itself, eg, #{item.icon} returns the icon image for a specific file type.



As I said at the beginning of this post, we don’t have access to the propertyMap object that is exposed by default when you are working with the Content Datacontrol or with Content Presenter. If you want to know more about this just take a look at the chapter Integrating Content of WebCenter Developer’s Guide that explains all the properties that you can use when working with Content Producers in WebCenter, more specifically, this table which lists Oracle UCM properties used by the content adapater.



So let’s add a new outputText. First of all, when you’re on customization mode you’re not able to edit a JSPX/JSFF by editing its source; you have to use the Visual Editor and the Property Inspector for that. From the Component Palette, drag and drop a new outputText just below the existing one:



CustomOutputText



Can you spot what’s strange in the picture above? The Value property is being represented as disabled, but fear not, if you click on the down arrow to the right and bring up the Expression Builder you will be able to change it – not the best usability example, I know. But also notice at the same time how JDev nicely indicates to which layer this customization is being applied. So bring up the Expression builder and enter the following expression:



#{'('}#{item.lastModifiedBy}#{')'}



Literal strings are not supported by MDS, so we need to surround them with EL or, better, use a Text Resource (resource bundle). For this example a Resource bundle is a bit overkill.



ExpressionBuilder



Select the rendered property, bring up the Expression Editor and enter the following expression:



#{!item.folder}



This will guarantee that the outputText won’t be rendered if it is a folder.



It is interesting to see here how the customization is stored by mds. Notice that it uses the same package structure as the basis for the customization, then is adds the mds namespace identifier (mdssys), the customization identifier (cust), the tip layer (site) and the layer value (webcenter).



LibCustomDelta



Then you can see that the xml file that has only the things you customized (the “delta”):





   1: <mds:customization version="11.1.1.55.36"



   2:                    xmlns:mds="http://xmlns.oracle.com/mds">



   3:   <mds:insert parent="dlPkVw" position="last"



   4:               xmlns:f="http://java.sun.com/jsf/core">



   5:     <f:facet xmlns:f="http://java.sun.com/jsf/core" name="bottom"/>



   6:   </mds:insert>



   7:   <mds:insert parent="dldpvpgl6" position="last"



   8:               xmlns:af="http://xmlns.oracle.com/adf/faces/rich">



   9:     <af:outputText xmlns:af="http://xmlns.oracle.com/adf/faces/rich"



  10:                    value="#{'('}#{item.lastModifiedBy}#{')'}" id="sot1"



  11:                    rendered="#{!item.folder}"/>



  12:   </mds:insert>



  13: </mds:customization>






Deploying the customization to MDS



Now that the actual customization is done we need to package it in a Metadata Archive (MAR) for deployment. From the Application Menu, select Application Properties



AppProp



… then select Deployment. Click on the [New…] button and select MAR File from the Archive Type listbox. Enter any meaningful name, eg, customFilePicker. Although it’s not required, I consider a good practice to uncheck all checkboxes in the Deployment panel to avoid any unwanted files in the archive:



DepProf



From the Application Menu, select Deploy > customFilePicker:



DeployCustom



Select the option to generate a jar file; currently you cannot deploy a MAR file from within JDev, so we need to use WSLT tool for that. If your WebCenter Spaces is running in a different machine than transfer the MAR file to it.



On your WebCenter Spaces installation home go to WEBCENTER_ORACLE_HOME/common/bin. In my case,it is /fmw/middleware/Oracle_WC1/common/bin . Now, run the wlst.sh or wlst.cmd script. Now you need to connect to the admin server by using the connect command:



wls:/offline> connect ('weblogic','welcome1','t3://ateam-hq67:7001')

Connecting to t3://ateam-hq67:7001 with userid weblogic ...
Successfully connected to Admin Server 'AdminServer' that belongs to domain 'wc_domain'.

Warning: An insecure protocol was used to connect to the
server. To ensure on-the-wire security, the SSL port or
Admin port should be used instead.

wls:/wc_domain/serverConfig>



Where weblogic is the admin user, welcome1 is the password and t3://ateam-hq67:7001 is the admin URL.



Before deploying our customization let’s create a new metadata label - MDS works much like a Version Control System. That way if we mess up the customization we can always revert back by using the promoteMetadataLabel command and avoid headaches. You create a label with the createMetadataLabel command:



wls:/wc_domain/serverConfig> createMetadataLabel('webcenter','WLS_Spaces','preCustomFilePicker');


Executing operation: createMetadataLabel.

Created metadata label "preCustomFilePicker".


Where webcenter is the application name, WLS_Spaces the server name, and preCustomFilePicker the metadata label.



And finally we import the MAR file with the importMetadata command:





   1: wls:/wc_domain/serverConfig> importMetadata(application='webcenter',server='WLS_Spaces',fromLocation='/tmp/customFilePicker.mar')



   2:  



   3: Executing operation: importMetadata.



   4:  



   5: Operation "importMetadata" completed. Summary of "importMetadata" operation is:



   6: List of documents successfully transferred:



   7:  



   8: /oracle/webcenter/doclib/view/jsf/fragments/mdssys/cust/site/webcenter/docPickerView.jsff.xml



   9:  



  10: 1 documents successfully transferred. 




When you enter the fromLocation attribute make sure to use the full file path – you cannot use relative paths.



All these commands have ANT tasks counterparts so you can script the whole process.



The cool part here is that you don’t need to bounce the server to see your new customizations in action!



Using the customized component!


You can test the customization by editing a page on WebCenter Spaces and adding a new Content Presenter document. Put the page in Edit Mode, then click on Add Content and from the Resource Catalog popup select Documents > Content Presenter. Remember that you will need an UCM instance connection configured for that:


ResourceCatalog



From the Content Presenter region, click on the little wrench icon to set up the content to be shown. From the popup, click the Content tab and then the Browse button. The file picker popup will show up with the customization:



CustomFinal



Now our file picker is showing up who has last modified the files stored in UCM.



What you should take from this post is not the exercise per se, but all the things involved when you’re customizing an application and how powerful it is. Hope that you enjoyed and can put it to good use!

3 comments: