Thursday, September 19, 2013

Mobilizing Your Portal Strategy @ OpenWorld 2013


Mobile portals must deliver much of the same capability available to desktop users and also provide unique capabilities pertinent to users on the move, all in a form that leverages mobile device capabilities and context signals. Although mobility raises new challenges for portal initiatives, it also brings a world of new opportunities to improve user engagement and business value. Attend this session to learn how Oracle WebCenter Portal is delivering mobile content creation, infrastructure, and collaboration to keep you connected on the go.
Additional Information

Oracle OpenWorld

MIDDLEWARE: Portal, Content Management, Web Experience Management, and Social Network

LOB Manager/Director, IT Manager

Conference Session


Venue / Room: Moscone West - 2016
Date and Time: 9/25/13, 13:15 - 14:15

Wednesday, September 18, 2013

Open the Navigation Link (defined in navigation model) in a New Window

A navigation link can be opened in the current window or a new window. By default it would open ni the current window. There are a number of the predefined URL attribute for a navigational resource. For a complete list of the URL attributes, please refer to here. One of the attribute is "Target". As per the description,  it's the location on the container page where the resource is displayed when it is selected, either in the same browser window (_self), a new window (_blank), or a popup (_popup), or any other location supported by the navigation UI.

Is that it? Not really, if you have custom developed your navigation UI.

The "target" attribute is nothing special here, as it's just an attribute with a meaningful name. The navigation UI needs to specifically evaluate the attribute and handle it.

Here are the two steps to do:

1. apply a swticher on the navigation model node. If the target is "_blank", use the golink component.


<af:switcher id="pt_sw2" facetName="#{(empty node2.attributes['Target']) || (node2.attributes['Target'] == '_blank) ? 'command' : 'golink'}">


2. in the goLink facet, apply the target attribute to the golink's target property.

<f:facet name="golink">
  <af:goLink id="pt_gl2" text="#{node2.title}"
             destination="#{node2.goLinkPrettyUrl}"
             targetFrame="#{node2.attributes['Target']}"/>
</f:facet>


Now we see why the "target" attribute in the navigational resource is not special.

Tuesday, September 17, 2013

Super Slowness on Content Presenting Rendering due to Large Number of Profiles, Region Definitions or Static Lists

Update:

The Oracle Patch on the bug has been released: Patch 17328920: CONTENT PRESENTER THROWS STUCK THREAD AND OOM WHEN UCM RETURNS MANY PROFILES.

 In this fix, a system parameter "contentTypeLazyCaching=true" is requested to be added on the JVM startup.

Custom code has been added into the ContentTypeFactory.class in the two places:
  • %ORACLE_HOME%/webcenter/modules/oracle.webcenter.content.integration_11.1.1/ucm_spi.jar/oracle/webcenter/content/integration/spi/ucm/factory/ContentTypeFactory.class
  • %ORACLE_HOME%/webcenter/modules/oracle.webcenter.content.integration_11.1.1/content-app-lib.ear/APP-INF/lib/ucm_spi.jar/oracle/webcenter/content/integration/spi/ucm/factory/ContentTypeFactory.class
The directory could be either on your local Jdev folder or on the remote WebCenter portal server.

The added custom code is a new method getMinimalContentTypes():

  public synchronized List<ContentType> getMinimalContentTypes()
    throws RepositoryException
  {
    List typeNames = getTypeNames();
    List minContentTypes = new ArrayList();

    for (String typeName : typeNames)
    {
      if (!typeName.startsWith("IDC:Profile:"))
      {
        ContentType type = UCMCacheHelper.getContentType(this.repoName, typeName);
        if (type != null)
        {
          minContentTypes.add(type);
          continue;
        }

        try
        {
          type = buildContentType(typeName);

          minContentTypes.add(type);
          if (type.isSearchable())
          {
            this.searchableContentTypes.add(typeName);
          }

        }
        catch (NoSuchContentTypeException re)
        {
          logger.log_NO_SUCH_CONTENT_TYPE_BY_NAME_ERROR(typeName, re);
        }
      }
    }
    return minContentTypes;
  }

  private void ensureAllContentTypesLoaded() {
    try {
      if (this.contentTypeLazyCaching)
        getMinimalContentTypes();
      else
        getAllContentTypes();
    }
    catch (RepositoryException re) {
      throw new RepositoryRuntimeException(re);
    }
  }


So instead of get all content types, the custom code bypasses all the profile content types as all profile content type starts with "IDC:Profile:".

This fix actually resolves the content presenter issue on the customer's environment. But it's not the final fix yet. As VCR_GET_CONTENT_TYPES returns all profiles, region definitions and static lists on the UCM server, the large number of region definitions and static lists could also cause additional performance problem.

More to come on the final resolution to this problem.

====================================================================
Original Post:

Content presenting is a great feature introduced in WebCenter 11g. As Portal can create its own content display template, it makes the feature very powerful to present content data file in ADF-native way. It also allows the region template (created in site studio) to be reused in WebCenter Portal and make it even greater. During my recent practice, I have come across a bug on the content presenting rendering in a very long time if the content server (UCM) contains a large number of profiles, region definitions or static lists.

In my target environment (11.1.1.7.1), the content server has over 1800 profiles, over 100 region definitions and 10-20 static lists. Using the OOTB content presenter task flow, to render a HTML file (less than 1 Kb) would take around 35-40 minutes!!!

This problem is only happening to content presenter task flow not other document task flows. The issue wasn't tested on 11.1.1.8 but it should be replicable on 11.1.1.8 as well.

After troubleshooting, we found when content presenter task flow tries to consume a content file, it sends request to the UCM server. UCM will initiate the following service call in sequence:

VCR_GET_DOCUMENT_BY_NAME
VCR_GET_CONTENT_TYPES
VCR_GET_CONTENT_TYPE
VCR_GET_CONTENT_TYPE
......
GET_ADVANCED_SEARCH_OPTIONS
GET_USER_PERMISSIONS
GET_FILE

The problem happens at the "ellipsis". The service call VCR_GET_CONTENT_TYPES (in plural) will return a collection of all the profiles, regions definitions and static lists in the content server. Then it's followed by looping through of the collection of the result set with one VCR_GET_CONTENT_TYPE call. Therefore if the VCR_GET_CONTENT_TYPES returns 2000 rows, it will result in 2000 calls on VCR_GET_CONTENT_TYPE. That's why it's causing the super slowness in the content presenting rendering.

To find out how many rows that the result set from VCR_GET_CONTENT_TYPES return, simply do a service call:  http://ucmhost:port/cs/idcplg?IdcService=VCR_GET_CONTENT_TYPES&IsSoap=1



Such call only happens once which is the first time a content is consumed by the content presenter task flow. The result set of the all content types will be saved in cache and serves for subsequent requests. Therefore such implementation is intended caching, but it certainly didn't consider the scenario of large number of the profiles, etc.

Currently the issue is filed as an Oracle bug (17328920) and the fix is soon to be released.

There are two temporary workarounds before the official fix is released.

1. Reduce the # of the profiles, region definitions and static lists. If you can reduce the total # of such assets down to 40-50, you should be fine. As you increase the #, you would expect to see increased degradation of the performance on the first time rendering. This is not an option if total # of the assets cannot be reduced.

2. Customize the VCR_GET_CONTENT_TYPES service call and make it only return a subset of the profiles, region definitions and static lists. This requires an evaluation of the WebCenter Portal application to determine what profiles, region definitions and static lists are required. Those required elements have to be part of the result set from the service call. Otherwise, errors like "resource not found" would be thrown.

I will update the post again once the official bug fix is released.

Monday, September 16, 2013

Filtering Navigation Links in the Navigation Model of WebCenter Portal

Background: It's well documented in the Oracle documentation that Resource Catalog can be filtered at the resource level and catalog level (link here). Let me re-iterate the details a little bit.
  • Resource level: there is a "visible" property that takes expression language as a value, which are evaluated at the run time as boolean value to determine whether the particular resource should be displayed or not. The value can be "#{true}", "#{false}" or any other valid EL.
  • Catalog level: we can define a Java Bean (a filter class) implementing CatalogDefinitionFilter to apply on a catalog.xml file. In this Java file, we need to implement the API includeInCatalog() which takes two arguments: catalogElement and hashtable objects. The filter class is triggered when the catalog is instantiated. 
Although not documented in the Oracle documentation, we could apply the same resource level and catalog level filtering on the navigation model. For any EL based checking, we can use the resource level filtering. But in a scenario that we need to pass a non-user or non-applicationContext parameters into the filtering logic, the EL is not a solution. We will need to use the catalog level filtering.

Scenario:This blog is demonstrating how to filter a navigation resource in a navigation model using an arbitrary parameter.

Solution:
1. Create a Java class in your portal project called "NavigationFilter" and implement "oracle.adf.rc.spi.plugin.catalog.CatalogDefinitionFilter". The API includeInCatalog() boilerplate code will be created.
2. Create two portal pages called "SecondPage" and "ThirdPage". Assign anonymous access to those page via jaza-data.xml.
3. Drag the two pages into the default-navigation-model.xml file. Define a parameter in the URL parameters section called "showFlag" and assign a value "Y" to the SecondPage, and "N" to the ThirdPage.

4. Copy the following code into the NavigationFilter Java class:

    public boolean includeInCatalog(CatalogElement catalogElement, Hashtable hashtable) {
       
        if (catalogElement.getId()!= null && !catalogElement.getId().equalsIgnoreCase("pages")) {
            ElementParameters params = catalogElement.getLocalParameters();   
            if (params != null) {
                String param = params.get("showFlag").getValue();
                if (param != null && param.trim().equalsIgnoreCase("Y")) {
                    return true;   
                } else {
                    return false;   
                }
            }
           
        }
        return true;
    }


5. At the default navigation model root level, define the Navigation Filter as the NavigationFilter Java class.


6. Run the app. Now you can see the SecondPage link will be rendered but not the ThirdPage link.

The Demo app can be downloaded here (Built on JDev 11.1.1.7)