Tuesday, April 19, 2011

WebCenter Navigation: Linking between nodes

The WebCenter PS3 release introduced the "Navigation Model" concept.  You can see the sort of navigation that you can create in John Brunswick's post.

One feature in the navigation model is an "ExtenalId" attribute.  This attribute allows you to have a direct reference to node within the navigation model without having to go through the parent nodes.
However, you can actually use the node directly within the navigation model itself.  This means you can have nodes that reference other nodes and create something similar to a symbolic link between nodes.

eg:  If you have a basic navigation model listing a number of pages, you can reference any of these pages by adding an "ExternalId" attribute to it.  See the bolded entries below:


    <url factoryClass="oracle.webcenter.portalframework.sitestructure.rc.AdfPageResourceFactory"
         url="page://oracle/webcenter/portalapp/pages/hr.jspx"
         id="HumanResources"
         visible="#{true}">
      <attributes>
        <attribute attributeId="Title" isKey="false" value="Human Resources"/>
        <attribute attributeId="ExternalId" isKey="false"
                   value="humanResources"/>

      </attributes>
    </url>
    <url factoryClass="oracle.webcenter.portalframework.sitestructure.rc.AdfPageResourceFactory"
         url="page://oracle/webcenter/portalapp/pages/customerService.jspx"
         id="CustomerService" visible="#{true}">
      <attributes>
        <attribute attributeId="Title" isKey="false" value="Customer Service"/>
      </attributes>
    </url>
    <url factoryClass="oracle.webcenter.portalframework.sitestructure.rc.AdfPageResourceFactory"
         url="page://oracle/webcenter/portalapp/pages/support.jspx" id="Support"
         visible="#{true}">
      <attributes>
        <attribute attributeId="Title" isKey="false" value="Support"/>
      </attributes>
    </url>
    <url factoryClass="oracle.webcenter.portalframework.sitestructure.rc.UrlResourceFactory"
         id="linkToHumanResources" visible="#{true}" url="wcnav_externalId/humanResources">
      <attributes>
        <attribute attributeId="Title" isKey="false"
                   value="Link To Human Resources"/>
      </attributes>
    </url>

When you click on "Link To Human Resources" the current selection will be set to the actual "Human Resources" node and will navigate to that node.  This is all done within the request so there is no re-direct required.

You can use this feature to also link from a parent entry to a desired child.  eg: 

    <url factoryClass="oracle.webcenter.portalframework.sitestructure.rc.UrlResourceFactory"
         id="ContactUs" visible="#{true}" url="wcnav_externalId/humanResources">
      <attributes>
        <attribute attributeId="Title" isKey="false"
                   value="Contact Us"/>
      </attributes>
      <contents>
        <url factoryClass="oracle.webcenter.portalframework.sitestructure.rc.AdfPageResourceFactory"
             url="page://oracle/webcenter/portalapp/pages/support.jspx"
             id="Support" visible="#{true}">
          <attributes>
            <attribute attributeId="Title" isKey="false" value="Support"/>
          </attributes>
        </url>
        <url factoryClass="oracle.webcenter.portalframework.sitestructure.rc.AdfPageResourceFactory"
             url="page://oracle/webcenter/portalapp/pages/hr.jspx"
             id="HumanResources" visible="#{true}">
          <attributes>
            <attribute attributeId="Title" isKey="false"
                       value="Human Resources"/>
            <attribute attributeId="ExternalId" isKey="false"
                       value="humanResources"/>

          </attributes>
        </url>
        <url factoryClass="oracle.webcenter.portalframework.sitestructure.rc.AdfPageResourceFactory"
             url="page://oracle/webcenter/portalapp/pages/customerService.jspx"
             id="CustomerService" visible="#{true}">
          <attributes>
            <attribute attributeId="Title" isKey="false"
                       value="Customer Service"/>
          </attributes>
        </url>
      </contents>
    </url>

ADF Faces and that annoying session timeout popup

OK, you've all seen this and it's really annoying.  When the ADF session is about to timeout you get the popup appearing 2 mins before.  Then, if you don't click on it, it gets replaced with the actual session timeout popup.

While I understand the need to tell the user that the session is about to timeout, there should be some way to control this behavior.  Yes, you do need to code to handle the session timeout but at least the user shouldn't be bothered by it and they should just be asked to re-login (if required) or not notice the session timed out if they are an anonymous user.

There is a way to stop the popup occurring documented at: http://download.oracle.com/docs/cd/E17904_01/web.1111/b31973.pdf (see section 8.2.5).  While the doc says:

"StateSaving: Set to the type of state saving you want to use for a page.
...

However, there may be a page for which you which you want the state saved differently. For example, when a user posts back to a login page after an extended period of time, you do not want the session time out error to be displayed. By changing the stateSaving attribute on the page to client, then when the user posts back to the login page, the time out error will not display."


That's not exactly true.  All you are dealing with here is the view state.  All the controller state and everything else is still expecting the session to exist on the server and you'll end up crashing if you rely on this alone.

The bottom line is that you can turn off the popup using web.xml settings (see below) but then need to manage the session expiry yourself. This can be done if you follow Frank Nimphius's post on Detecting and handling user session expiry.  His post has you going to a specific page but you can also redirect to any URL including the request URL and get the behavior you want.


sample entries:
  • web.xml
    •   Session Timeout for debug
      • <session-config>
            <session-timeout>1</session-timeout>
          </session-config>
      • This is for debug so it times out after one minute.  *Don't Leave This In There*!
    • Turn off the popup
      •   <context-param>
            <param-name>org.apache.myfaces.trinidad.CACHE_VIEW_ROOT</param-name>
            <param-value>false</param-value>
          </context-param>
          <context-param>
            <param-name>org.apache.myfaces.trinidad.USE_APPLICATION_VIEW_CACHE</param-name>
            <param-value>false</param-value>
          </context-param>
          <context-param>
            <param-name>org.apache.myfaces.trinidad.CLIENT_STATE_METHOD</param-name>
            <param-value>all</param-value>
          </context-param>
          <context-param>
            <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
            <param-value>client</param-value>
          </context-param>
      • The setting of STATE_SAVING_METHOD to "client" will cause the popup to stop appearing
    • Create a filter to handle what happens when the session times out
      •   <filter>
            <filter-name>ApplicationSessionExpiryFilter</filter-name>
            <filter-class>portal.ApplicationSessionExpiryFilter</filter-class>
            <init-param>
              <param-name>SessionTimeoutRedirect</param-name>
              <param-value>SessionHasExpired.jspx</param-value>
            </init-param>
          </filter>
          <filter-mapping>
            <filter-name>ApplicationSessionExpiryFilter</filter-name>
            <servlet-name>Faces Servlet</servlet-name>
          </filter-mapping>

JDeveloper, WebCenter and MDS: Uploading/Downloading from an MDS database store

The previous posts on this topic tell you how to avoid using the MDS database store.
In a production system, you still need to be able to get at your MDS data in the database.

There are standard WLST commands to upload/download MDS data but there is also a built-in utility "mdstransfer", which also allows you to manage this data. 

This utility can be found under your JDeveloper install directory. Typically under:  jdeveloper/mds/bin/mdstransfer

The tool is fairly straightforward and takes a parameter file as input to define the source & target of the transfer operation along with the namespace to retrieve the data.

eg: To transfer all data from the MDS repository to a file to /tmp/end_data, create the following files:

tofile.sh
#!/bin/sh
$ORACLE_HOME/jdeveloper/mds/bin/mdstransfer "/**" --paramfile tofile.xml

tofile.xml - Replace the bold entries

<!--
Transfer documents from a directory to DB MetadataStore
-->
<parameters xmlns="http://xmlns.oracle.com/mds/config_10_1_3_001">

<source-store>
 <metadata-store class-name="oracle.mds.persistence.stores.db.DBMetadataStore">
   <property name="jdbc-userid" value="<username>"/>
   <property name="jdbc-password" value="<password>"/>
   <property name="jdbc-url" value="jdbc:oracle:thin:@<server>:<port>/<sid>"/>
   <property name="partition-name" value="<MDS partition name used on deploy>"/>
 </metadata-store></source-store>
 <target-dir value="/tmp/end_data"/>
 <associated-docs>
   <customizations>
     <include-all-customizations value="true" />
   </customizations>
   <translations>
     <include-all-translations value="false"/>
   </translations>
   <extended-metadata exclude="true"/>
 </associated-docs>
</parameters>

Make sure the destination directory exists and run the script:

>mkdir /tmp/end_data
>./tofile.sh


To upload to the Database store from the filesystem create the following files.  This is just the same as the previous entry but with the switched to source-store/target-dir parameters changed to source-dir/target-store:

todb.sh
#!/bin/sh
$ORACLE_HOME/jdeveloper/mds/bin/mdstransfer "/**" --paramfile todb.xml

todb.xml - replace the bold entries

<parameters xmlns="http://xmlns.oracle.com/mds/config_10_1_3_001">
<source-dir value="/tmp/end_data"/>
<target-store>
 <metadata-store class-name="oracle.mds.persistence.stores.db.DBMetadataStore">
   <property name="jdbc-userid" value="<username>"/>
   <property name="jdbc-password" value="<password>"/>
   <property name="jdbc-url" value="jdbc:oracle:thin:@<server>:<port>/<sid>"/>
   <property name="partition-name" value="<MDS partition name to deploy to>"/>
 </metadata-store>
</target-store>
<associated-docs>
  <customizations>
    <include-all-customizations value="true" />
  </customizations>
  <translations>
    <include-all-translations value="false"/>
  </translations>
  <extended-metadata exclude="true"/>
</associated-docs>
</parameters>

 Run the script
>./todb.sh

Monday, April 18, 2011

JDeveloper, WebCenter and MDS: File vs. Database Store

Oracle's Metadata Services (MDS) offers two options for storing metadata:  File or Database.   In a production system, only the Database is configured and supported.  In JDeveloper, only the Filesystem is configured.

This isn't normally an issue but if you want to debug what is going on in MDS when you make a customization, using WLST commands to download the MDS contents from the Database can be tiresome.

Another alternative is to configure an MDS filesystem store on the server and use that when deploying the application.  While it's not supported in a production system, it at least allows you to easily see what is being created.  In fact this is what JDeveloper already does when you deploy an application to it's built-in server rather than just clicking on the "run" button.

To see the JDeveloper configured MDS connection information, start up the Server Instance from the "Run" menu item and access the console at:  http://127.0.0.1:7101/console  (weblogic/weblogic1)



Under: "Services->Persistent Stores" you will see the pre-configured MDS connection "mds-integServerRepos"

Selecting this "Persistent Store" will show you the directory that MDS will write to for applications deployed to this server.

Since MDS already supports deploying to a filessystem store (even if it doesn't support running to one), you can do the same thing in your standalone server.

The trick here is that all Data Sources & Persistent Stores with a prefix of "mds-" will be offered as an option when you deploy from JDeveloper.  If your app is configured to use MDS, a dialog will popup during deployment requesting the MDS store to use for the deployed application.
To create your own Filesystem store in the deployment environment, create a new persistent store prefixed with "mds-" and point it to an existing directory.
All files added to the Metadata Archive (MAR) file will now be created as files in your MDS Filesystem directory. Likewise, all customizations and new base documents will also appear in this directory.

JDeveloper, WebCenter and MDS: Write Directory

With PS3 of JDeveloper, WebCenter introduced a configured "Portal" application.  This out-of-the-box application runs immediately from JDeveloper.  It can also be further modified at runtime through the "administration" link after logging in as "weblogic/weblogic1". 



Looking under the covers, the JDeveloper application that gets created is using Oracle's MDS (Metadata Services) layer to store customizations and new base documents in a configurable "write" directory.  
To view this folder, look under the "Application Properties" and select "Run->MDS" from the dialog


Details of this dialog can be found in the doc but it's basically just telling you where all those changes you make at runtime are stored.  It also allows you to maintain those runtime changes between runs but beware that these values aren't included when the application is deployed.  It's like a little local sandbox you can play in while developing the app.

Base documents are under the resource directory:
>./oracle/webcenter/portalapp/pagehierarchy/Page1.jspx
>./pageDefs/oracle/webcenter/portalapp/pagehierarchy/Page1PageDef.xml

Customizations to base documents end up in an "mdssys" directory:
>./oracle/webcenter/portalapp/pagehierarchy/mdssys/cust/site/site/pages.xml.xml
>./oracle/webcenter/portalapp/pagehierarchy/mdssys/cust/site/site/Page1.jspx.xml

One word of warning;  if you turn on the "Preserve customizations across applications runs" option then the customization or base document change may hide any changes you make to the same document at design-time.