44 Integrating Third-Party Content Sources Using Proxy Assets

Content and marketing teams often need to publish content that resides outside websites developed with WebCenter Sites. You can enable them to integrate external web content using the proxy asset type framework.

Topics:

44.1 Proxy Asset Architecture and the Contributor Interface

In the proxy asset architecture, you make a third-party content repository accessible from the editorial and delivery instances and customize the contributor interface to access this repository.

Proxy Asset Architecture

A proxy asset is an asset representing content stored and managed in a remote location. This figure shows the proxy asset architecture:

Figure 44-1 Proxy Asset Architecture

Description of Figure 44-1 follows
Description of "Figure 44-1 Proxy Asset Architecture"

In this architecture:

  • A third-party content repository is assumed, accessible through a public read API from both the editorial and delivery instances.

  • The Contributor interface is customized to access the third-party repository to make external content visible in the UI.

  • A proxy asset is created on the fly for every external content rendered in the UI. A proxy asset does not store any metadata, which is assumed to be accessible through a public read API provided by the third-party service.

  • On the live instance, templates written for proxy assets are accessing the same repository and API to render external content on the live site.

Note:

Only those proxy assets that are used are permanently stored in the WebCenter Sites database. For example, proxy assets created while rendering search results are later purged by a dedicated cleaning event.

Contributor Interface

Once a new proxy asset type is registered in the WebCenter Sites database, developers have to provide the appropriate UI customizations before contributors can start interacting with external content.

The nature of the UI customizations being implemented depend on the contributor's specific requirements. For example, it is expected that the Contributor interface search functionality is hooked to the external repository's own search service in most cases.

After this is done, and external content is surfaced in the Contributor interface in the form of proxy assets, they behave mostly like standard assets. That is, contributors are able to:

  • Search the external content repository, using the same asset search tab, showing results in list or thumbnail view, docked or undocked.

  • Use drag and drop from search or tree.

  • Associate external content to other assets, whether in form view or web view.

  • Preview external content, using WebCenter Sites templates.

  • Bookmark, tag, set in workflow, approve, and publish.

Note:

The following restrictions apply:

  • The external content lifecycle is assumed to be entirely managed in a third-party UI; that is, WebCenter Sites only needs read access to the external repository. Consequently, UI actions such as editing, versioning, and so forth, are disabled by default for all proxy asset types.

  • Proxy assets cannot have associated assets or subtypes.

  • The external content repository must be accessible from both the contribution and delivery WebCenter Sites instances.

44.2 Installing Sample Proxy Assets

To install proxy assets in Oracle WebCenter Sites, you begin with setting up a proxy asset directory and creating a proxy asset.

44.2.1 Set up a Proxy Asset Directory

To set up a proxy asset directory:
  1. In your Oracle WebCenter Sites installation, navigate to sites-home\bootstrap\samples\miscellaneous\SampleProxy\proxy_sample. In the subsequent steps this directory is referred to as ${WCS_PROXY}.
  2. Copy the proxy_samples directory under the web application root on the server. For example, sites-webapp-server\webapps\sites\proxy_samples.
    This directory contains the sample JSON and images to simulate a third-party API.
  3. To test the proxy_samples directory, start the server and navigate to http://localhost:8080/sites/proxy_samples/search/ski.json. Then click one of the files in your browser to see the JSON text.

44.2.2 Create a Proxy Asset

To create a proxy asset:
  1. Log into WebCenter Sites and launch the Admin interface.
  2. Expand Admin, then Proxy Asset Maker, and then double click Add New.
  3. In the form, enter values in these fields: Name (e.g: ProxyTest), Description, and Plural Form (e.g.: ProxyTests) for the proxy asset.
  4. Click Save.
  5. Enable the ProxyTest asset in your site. To do this, create a Search start menu for ProxyTest.
    You cannot yet access the ProxyTest Search start menu in the Contributor interface.

44.2.3 Add the Search Functionality for the Proxy Asset

To add the search functionality:
  1. Open Sites Explorer and log in to your WebCenter Sites instance.
  2. In Sites Explorer, under Tables/ElementCatalog/CustomElements, create the following directory structure: ProxyTest/UI/Data/Search:
    Shows this Sites Explorer directory structure: Tables/ElementCatalog/CustomElements.
  3. Under ProxyTest/UI/Data/Search, add two new rows.
  4. Copy and paste the contents from the corresponding files in ${WCS_PROXY}\src\jsp\cs_deployed\CustomElements\ProxyTest\UI\Data\Search and save:
    • SearchAction
      • elementname: SearchAction

      • url: CustomElements\ProxyTest\UI\Data\Search\SearchAction.jsp

    • SearchJson

      • elementname: SearchJson

      • url: CustomElements\ProxyTest\UI\Data\Search\SearchJson.jsp

  5. In Sites Explorer, under ElementCatalog, add ProxyTest: Tables\ElementCatalog\ProxyTest.
  6. Under Tables\ElementCatalog\ProxyTest, create a new entry by copying and pasting the contents from ${WCS_PROXY}\src\jsp\cs_deployed\ProxyTest\GetData.jsp : GetData (elementname: GetData, url: ProxyTest/GetData.jsp), and then save these changes.
  7. In the Contributor interface, in the Search field for ProxyTest, enter ski, surfing, or nothing.
    You should see a list populated with proxy assets.

44.2.4 Add the Thumbnail Grid Functionality for the Proxy Asset

To add the thumbnail grid functionality:
  1. In Sites Explorer, under Tables\ElementCatalog\CustomElements\ProxyTest\UI, create the following folder structure: \Layout\CenterPane\Search\View.
  2. Add the following entries by copying and pasting the contents from the corresponding files in ${WCS_PROXY}\src\jsp\cs_deployed\CustomElements\ProxyTest\UI\Layout\CenterPane\Search\View.
    • ThumbnailViewConfig:
      • elementname: ThumbnailViewConfig

      • url: CustomElements\ProxyTest\UI\Layout\CenterPane\Search\View\ThumbnailViewConfig.jsp

    • DockedThumbnailViewConfig:

      • elementname: DockedThumbnailViewConfig

      • url: CustomElements\ProxyTest\UI\Layout\CenterPane\Search\View\DockedThumbnailViewConfig.jsp

  3. In the Contributor interface, enter a valid search term for ProxyTest assets.
    You will see the thumbnail images in the grid mode.

44.2.5 Add the Tree Functionality for the Proxy Asset

To add the tree functionality:
  1. In Sites Explorer, under Tables\ElementCatalog\ProxyTest, create a directory called Tree.
  2. Add the following entries by copying and pasting the contents from the corresponding files in ${WCS_PROXY}\src\jsp\cs_deployed\ProxyTest\Tree.
    • Load

      • elementname: Load

      • url: ProxyTest\Tree\Load.jsp

    • Root

      • elementname: Root

      • url: ProxyTest\Tree\Root.jsp

  3. Switch to the Admin interface.
  4. Add a tree tab:
    1. Expand the Admin node.
    2. In the tree, double-click Tree.
      The Tree Tabs page is displayed.
    3. Click Add New Tree Tab.
    4. Enter the following:
      • In the Title field, enter ProxyTestTreeTab.

      • In the Sites box, choose avisports (or whichever site you're using).

      • In the Required Roles box, choose Any.

      • In the Tab Contents box, select ProxyTest and click Add Selected Items.

      • In the selected box, click ProxyTest.

      • In the Section Name field, enter ProxyTest.

      • In the Element Name field, enter ProxyTest/Tree/Root ( use only forward slashes).

      • Click Edit Section, then click Save.

  5. Switch to the Contributor interface.
  6. On the Content Tree, and expand the ProxyTestTreeTab tree tab.
    You should see the categories ski and surfing available for drag and drop, along with their respective assets.

44.3 Integrating External Content in the Contributor Interface

Contributors will be able to work with external content when you’ve integrated the external content repository with the repository search service and content tree.

In this topic, we'll use the ProxyTest content repository as a case study and explain the steps to integrate it with:

  • Search: To use the repository search service instead of the standard WebCenter Sites search.

  • Content tree: To allow contributors to browse the repository content in a custom content tree.

Topics:

44.3.1 Case Study: The ProxyTest Repository

This section describes setting up sample data and retrieving data from the ProxyTest repository.

Setting Up Sample Data

We're using a set of static JSON files deployed directly in the WebCenter Sites web application to emulate the ProxyTest content repository. The ProxyTest content is assumed to be media content (images).

Those JSON files simulate the following services:

  • Search the repository for a given term (searching on all, ski or surfing returns actual results): http://localhost:7001/sites/proxy_samples/search/<searchterm>.json

  • Get all content categories (Ski and Surfing): http://localhost:7001/sites/proxy_samples/browse/categories.json

  • Get all ProxyTest content for a given category: http://localhost:7001/sites/proxy_samples/browse/<category>.json

  • Get metadata for a given content ID: http://localhost:7001/sites/proxy_samples/content/<id>.json

For example, /proxy_samples/search/ski.json returns the following example content:

{
  "items": [
    {
      "id": "1001", 
      "title": "Yellow Skier",
      "foo": "bar1",
      "lastModified": "1354735336444",
      "thumbnail": "proxy_samples/images/image7_thumbnail.png"
    },
    {
      "id": "1002", 
      "title": "Female Skier",
      "foo": "bar2",
      "lastModified": "1354735336444",
      "thumbnail": "proxy_samples/images/image8_thumbnail.png"
    },
    {
      "id": "1003",
      "title": "Ski Jump",
      "foo": "bar3",
      "lastModified": "1354735336444",
      "thumbnail": "proxy_samples/images/image9_thumbnail.png"
    }
  ]
}

Note:

Sample code is stored in the folder /misc/proxy_samples/. This folder is located in sites-home\bootstrap\proxy_samples\miscellaneous\SampleProxy. Sample code specific to proxy assets is here: sites-home\bootstrap\samples\miscellaneous\SampleProxy\proxy_samples\.

Retrieving Data from the ProxyTest Repository

To avoid duplication of code, logic needed to query the external content source is encapsulated in a dedicated element named ProxyTest/GetData. In this example, data is returned in JSON format. Therefore, this example uses the jersey (http://jersey.java.net/) and jettison (http://jettison.codehaus.org/) libraries, deployed in the WebCenter Sites web application, to retrieve and deserialize incoming JSON data.

The element receives a query, for example, /search/ski.json, in an ICS variable named serviceURL and returns a JSONArray object stored in the ICS scope using ics.SetObj(String, Object):


<%@ taglib prefix="cs" uri="futuretense_cs/ftcs1_0.tld"
%><%@ taglib prefix="ics" uri="futuretense_cs/ics.tld"
%><%@ page import="javax.ws.rs.client.*" 
%><%@ page import="javax.ws.rs.core.*" 
%><%@ page import="org.codehaus.jettison.json.*"
%><cs:ftcs>
<%
//
// get data from proxytest repository
// 
// 

Client client = ClientBuilder.newClient();
Response resp = null;
WebTarget res = null;


String host = request.getServerName();
String port = Integer.toString(request.getServerPort());
String contextPath = request.getContextPath();
String urlPath = "http://"+host+":"+port+"/"+contextPath+"/proxy_samples" + ics.GetVar("serviceURL");


try {
      res = client.target(urlPath);
      resp = res.request(MediaType.APPLICATION_JSON).get();
}
catch(Exception e) {
      e.printStackTrace();
      throw e;
}

JSONArray list = new JSONArray();

if (resp.getStatus() == 200) {
      String jsonString = resp.readEntity(String.class);
      JSONObject json = new JSONObject(jsonString);
      list = json.getJSONArray("items");
}

ics.SetObj("items", list);

%>

</cs:ftcs>

44.3.2 Registering a New Proxy Asset Type

To represent ProxyTest content in the WebCenter Sites repository, define a new proxy asset type.

To create a proxy asset type:

  1. On the Admin node, expand Proxy Asset Manager, and double-click Add New.

    The Add New Proxy Asset Type page opens.

    Figure 44-2 Add New Proxy Asset Type Page

    Description of Figure 44-2 follows
    Description of "Figure 44-2 Add New Proxy Asset Type Page"
  2. In the Name field, enter a name for the proxy asset type. Similarly, enter a description in the Description field, and enter a plural form of the name in the Plural Form field.

    Note:

    Creating or editing proxy assets through the Contributor interface is not available. Consequently, in this step, only a Search start menu should be enabled.

    In this example, and to use with the examples continuing through the rest of the document, enter ProxyTest in the Name field, ProxyTest in the Description field, and ProxyTests in the Plural Form field.

  3. Click Save.

Note:

Proxy Asset Maker registers the new asset type and creates a single table with the same name. A proxy asset table has only a subset of standard asset metadata, and defines only one specific column: externalid. This column is meant to store the identifier of the external content in the external repository.

44.3.3 About Implementing UI Integration Code

Assets can appear in many places in the Contributor interface. Some examples of these places include:

  • Asset forms, for fields including asset references

  • Search results

  • Content tree panel

In each case, the actual integration code varies based on the requirements and available customization hooks. However, in all cases, the following principle must be followed: All external content presented in the Contributor interface must be registered as a proxy asset.

In practice, this means creating (or reusing) a proxy asset which externalid refers to the content identifier in the external content source. This can be done using the usual Asset API classes and methods. However, for simplicity, the proxy JSP tag library is provided.

It contains utility tags to register a given external content as a proxy asset type:

  • <proxy:register />

It also contains utility tags to generate a JSON datastore for data grid widgets (such as search):

  • <proxy:createstore />: Initializes a new store.

  • <proxy:addstoreitem />: Adds an item to a given store.

  • <proxy:tojson />: Serializes a store to JSON.

See the Tag Reference for Oracle WebCenter Sites Reference and the code examples in Customizing Search.

44.3.4 Customizing Search

As explained in Customizing the Search Start Menu, an override of the controller element UI/Data/Search/Search for the ProxyTest asset type is created using the following elements:

\sites-home\bootstrap\samples\miscellaneous\SampleProxy\proxy_sample\src\jsp\cs_deployed\CustomElements\ProxyTest\UI\Data\Search\SearchAction.jsp
\sites-home\bootstrap\samples\miscellaneous\SampleProxy\proxy_sample\src\jsp\cs_deployed\CustomElements\ProxyTest\UI\Data\Search\SearchAction.jsp\SearchJson

The figure below shows the ProxyTest option in the search drop-down. Selecting ProxyTest (that is, the name of the proxy asset type created) runs the custom search code, instead of the Lucene-based search.

Figure 44-3 Search Drop-Down Showing ProxyTest Asset

Description of Figure 44-3 follows
Description of "Figure 44-3 Search Drop-Down Showing ProxyTest Asset"

To implement a full custom search, complete the remaining topics in this section.

This topic includes the following:

44.3.4.1 Getting Search Results Using the Provided Third-Party API
  1. In CustomElements/ProxyTest/UI/Data/Search/SearchAction, retrieve the JSON data using the element written in Case Study: The ProxyTest Repository.

    Use this code example in the retrieval:

    <%@ taglib prefix="cs" uri="futuretense_cs/ftcs1_0.tld"%>
    <%@ taglib prefix="ics" uri="futuretense_cs/ics.tld"%>
    <%@ taglib prefix="proxy" uri="futuretense_cs/proxy.tld"%>
    <%@ page import="org.codehaus.jettison.json.*"%>
    <%@ page import="COM.FutureTense.Interfaces.Utilities"%>
    <cs:ftcs>
    
    <%
    // in this ProxyTest example, only the empty search string, 'ski' or 'surfing' will 
    // return results String searchTerm = ics.GetVar("searchText");
    if (!Utilities.goodString(searchTerm)) searchTerm = "all";
    %>
    <ics:setvar name="serviceURL" value='<%="/search/" + searchTerm + ".json" %>' />
    <ics:callelement element="ProxyTest/GetData" />
    <%
    JSONArray list = (JSONArray)ics.GetObj("items");
    
    //
    // ...to be continued in the next section
    //
    %>
    
    </cs:ftcs>
    
  2. At this point, list contains the JSON data received from the external content source.
44.3.4.2 Turning Search Results into Proxy Assets, Filter Incoming Search Results, Register External Content, and Gather Data for Search Grid Widget

This builds the code through a series of steps:

  1. Build a new data store:
    <proxy:createstore store="<storeName>" />
    

    where <storeName> is an arbitrary string designating the data store.

  2. Then, for each incoming external content asset, register the current asset as a proxy asset:
    <proxy:register
           externalid="<external_content_identifier>"
           type="<proxy_asset_type>"
           name="<proxy_asset_name>"
           varname="<variable_name>" />
    

    where:

    • <external_content_identifier> is the identifier of the current external content item in the third-party repository. In the case of this example ProxyTest repository, this identifier is returned in the id of incoming JSON data.

    • <proxy_asset_type> is the proxy asset type name. In this example, ProxyTest.

    • <proxy_asset_name> is the readable string to be used as name throughout the Contributor interface. In this example, the title returned in the incoming JSON data.

    • <variable_name> is the name of the WebCenter Sites variables that contain the proxy asset ID corresponding to the current external content item.

  3. Then, for each incoming registered proxy asset, add the asset to the data store:
    <proxy:addstoreitem 
           store="<storeName>"
           id="<proxy_asset_id>"
           type="<proxy_asset_type>" />
    

    where:

    • <storeName> is the data store, as defined by <proxy:createstore />.

    • <id> is the proxy asset identifier.

    • <type> is the proxy asset type.

The full code for the ProxyTest proxy asset type is then:

<%@ taglib prefix="cs" uri="futuretense_cs/ftcs1_0.tld"%>
<%@ taglib prefix="ics" uri="futuretense_cs/ics.tld"%>
<%@ taglib prefix="proxy" uri="futuretense_cs/proxy.tld"%>
<%@ page import="org.codehaus.jettison.json.*"%>
<%@ page import="COM.FutureTense.Interfaces.Utilities"%>
<cs:ftcs>

<%
// in this ProxyTest example, only the empty search string, 'ski' or 'surfing' will
// return results
String searchTerm = ics.GetVar("searchText");
if (!Utilities.goodString(searchTerm)) searchTerm = "all";
%>
<ics:setvar name="serviceURL" value='<%="/search/" + searchTerm + ".json" %>' />
<ics:callelement element="ProxyTest/GetData" />
<%
JSONArray list = (JSONArray)ics.GetObj("items");
%>

<%-- create a new data store --%>
<proxy:createstore store="assets" />
<%
// go through each incoming item
for (int i = 0; i < list.length(); i++) {
     JSONObject item = (JSONObject)list.get(i);%>

     <%-- Register the current external content item as a proxy asset --%>
     <proxy:register externalid='<%=item.getString("id") %>'
     type="ProxyTest"
     name='<%=item.getString("title") %>'
     varname="internalid" />

<%-- Add the proxy asset to the datastore --%>
<proxy:addstoreitem store="assets"
                    id='<%=ics.GetVar("internalid") %>'
                    type="ProxyTest" />
<%
}
// put store name in request scope
request.setAttribute("store", "assets");
request.setAttribute("total", Integer.valueOf(list.length()));
%>
</cs:ftcs>
44.3.4.3 Building a Data Store for the Grid Widget

This renders the JSON to be sent back to the UI widget.

Inside CustomElements/ProxyTest/UI/Data/Search/SearchJson, use the proxy:tojson utility tag does this, as shown in the following example:

<%@ taglib prefix="cs" uri="futuretense_cs/ftcs1_0.tld"%>
<%@ taglib prefix="proxy" uri="futuretense_cs/proxy.tld"%>
<cs:ftcs>
<proxy:tojson store="${store}" total="${total}" />
</cs:ftcs>
44.3.4.4 Testing Custom Search

After the JSON is scripted, test the search function to ensure everything works properly. To test the search:

In the Contributor interface, from the search box, select ProxyTest as the search type. Click the Search icon.

The Search tab opens displaying the associated data.

The following figure shows the same content in Thumbnail view.

Figure 44-5 Search Results in Thumbnail View

Description of Figure 44-5 follows
Description of "Figure 44-5 Search Results in Thumbnail View"

The Search tab also is functional in docked mode. The following figure shows that the tooltip is filled in with default data.

Figure 44-6 Search Results in Docked Panel

Description of Figure 44-6 follows
Description of "Figure 44-6 Search Results in Docked Panel"
44.3.4.5 Additional Customizations

You can implement additional customizations. However, it is not necessary to use them to implement a custom search.

Rendering a Thumbnail

In the example, the ProxyTest repository returns a URL to a thumbnail image for each content item. We modify it to retrieve the thumbnail URL (sent by our ProxyTest repository) to render it. For that to happen, we must customize the grid in thumbnail view (whether docked and undocked); that is, overriding the configuration elements for:

UI/Layout/CenterPane/Search/View/ThumbnailView
UI/Layout/CenterPane/Search/View/DockedThumbnailView

Configuration files for each must be created:

CustomElements/ProxyTest/UI/Layout/CenterPane/Search/View/ThumbnailViewConfig
CustomElements/ProxyTest/UI/Layout/CenterPane/Search/View/DockedThumbnailViewConfig

The ThumbnailViewConfig configuration file has the following XML configuration:

<%@ taglib prefix="cs" uri="futuretense_cs/ftcs1_0.tld" %> 
<%@ taglib prefix="xlat" uri="futuretense_cs/xlat.tld" %>
<cs:ftcs>
  <thumbnailviewconfig>
    <formatter>fw.ui.GridFormatter.simpleThumbnailFormatter</formatter>
  </thumbnailviewconfig>
</cs:ftcs>

You can see that this overrides the formatter setting for the ProxyTest thumbnail view (any other setting contained in the global configuration element is maintained). This formatter renders a default view for each search result showing a thumbnail image, and the name field (inspect link).

Similarly, docked thumbnail view settings should be overwritten by creating DockedThumbnailViewConfig in CustomElements/ProxyTest/UI/Layout/CenterPane/Search/View/ with the following XML:

<%@ taglib prefix="cs" uri="futuretense_cs/ftcs1_0.tld"%> 
<%@ taglib prefix="ics" uri="futuretense_cs/ics.tld"%> 
<cs:ftcs>
<ics:callelement element=
"[CustomElements/ProxyTest/UI/Layout/CenterPane/Search/View/ThumbnailViewConfig]" />
</cs:ftcs>

Note:

See Customizing Search Views of the Contributor Interface.

The brackets around the element name indicate that the ics:callelement tag should not search for a customized version of the given element name.

Configuring the Grid Context Menu

Not all asset operations apply to proxy assets. Therefore, we have to override the default grid context menu setup. Override the element UI/Config/GlobalHtml by creating new element MyConfig in UI/Config. For more information about creating MyConfig, see Customizing Context Menus.

This ensures that none of the global settings are merged with the overridden settings.

Sorting Proxy Assets by Fields

Sorting of proxy assets is done by the external content source API (WebCenter Sites does not sort results internally). Thus, there may or may not be any support for sorting all fields. A user can carry out a sorted search for proxy assets by clicking the Sort icon and choosing among the sort options.

Note:

The ProxyTest asset example does not support sorting.
This image shows proxy assets sorted by fields.

The sort options are set in CustomElements/ProxyTest/UI/Layout/CenterPane/Search/View/SearchTopBarConfig. You must define the following for the sort options:

  • fieldname: The value of the sort variable that is passed with the request object to SearchAction, which should indicate the field to sort on (e.g. date).

  • displayname: The string displayed in the Sort drop-down menu (e.g. View Count(Most-Least)).

  • sortorder: descending or ascending. If descending, WebCenter Sites adds a negative sign (-) in front of the fieldname value.

The following code is written for the YouTube proxy assets:

<%@ taglib prefix="cs" uri="futuretense_cs/ftcs1_0.tld"
%><%@ taglib prefix="xlat" uri="futuretense_cs/xlat.tld"
%><cs:ftcs>
    <!-- Here the field name is the index column on which the sort is performed.-->
    <sortconfig>
        <sortfields>          
            <sortfield id="title">
                <fieldname>title</fieldname>
                <displayname><xlat:stream key="UI/UC1/Layout/NameSort1" escape="true"/></displayname>
                <sortorder>ascending</sortorder>
            </sortfield>
            <sortfield id="updateddate_dsc">
                <fieldname>date</fieldname>
                <displayname><xlat:stream key="UI/UC1/Layout/ModifiedSort1" escape="true"/></displayname>
                <sortorder>descending</sortorder>        
            </sortfield>
            <sortfield id="viewCount">
                <fieldname>viewCount</fieldname>            
                <displayname><xlat:stream key="UI/UC1/Layout/ViewCountSort" escape="true"/></displayname>
                <sortorder>descending</sortorder>                
            </sortfield>
        </sortfields>
    </sortconfig>
</cs:ftcs>

After a sort field is chosen, a new sorted search is initiated and SearchAction is called. A sort parameter is available in the request object, which provides the field to sort by. For example, in the YouTube proxy asset SearchAction, the sort parameter is obtained and used as a query parameter value:

...

String sort = request.getParameter("sort");
if(sort != null && StringUtils.isNotEmpty(sort)){
    // incase of descending sort, UI sends the field with a -ve sign, 
    // YouTube doesn't take as is, so remove the -ve sign if any
    sort.trim();
    if(sort.startsWith("-")){
         sort = sort.substring(1,sort.length());
    }
}else{
    sort = "relevance";
}

...

// build YouTube URL
String baseYtURL = "https://www.googleapis.com/youtube/v3/";
StringBuffer ytQuery = new StringBuffer(baseYtURL);
ytQuery.append("search?part=snippet");
ytQuery.append("&maxResults=" + maxResults); // number of results per page
ytQuery.append("&type=video"); //only return videos, no channels or playlists
ytQuery.append("&order=" + sort); // ordering
ytQuery.append("&key=" + apiKey); // add user's API public access key
ytQuery.append("&q=").append(URLEncoder.encode(searchTerm));

...

Be aware that both SearchTopBarConfig and ContextMenuConfig elements must have merge=false set in the element resdetails1 (or resdetails2) field.

Figure 44-7 Configuration File Element Details Value Field

Description of Figure 44-7 follows
Description of "Figure 44-7 Configuration File Element Details Value Field"

44.3.5 Implementing a Custom Tree

A custom tree is useful to allow users to browse external content by category.

Two elements are created to render the tree:

  • ProxyTest/Tree/Root: Renders the tree root nodes, that is, the content categories.

  • ProxyTest/Tree/Load: Renders all content under a given category.

To implement the custom tree, you must first register the custom tree tab, and then implement the custom tree code.

This topic includes the following:

44.3.5.1 Registering the Custom Tree Tab

The custom tree tab is defined in the Add New Tree Tab page. With the tab created in this example, a new content tree called Proxy Assets is created, containing a single custom section (ProxyTest) pointing at ProxyTest/Tree/Root.

To register the custom tree tab for this example:

  1. In the Admin interface, expand the Admin node, then double-click Tree.

    The Tree Tabs page opens.

  2. At the bottom of the Tree Tabs page, click Add New Tree Tab.

    The Add New Tree Tab page opens.

  3. Fill in the fields as needed. For this specific example, fill in the fields in this way:
    • Title: Enter Proxy Assets for the title of the tab.

    • Sites: Select Proxy from the list.

    • Required Roles: Select Any from the list.

    • Tab Contents: Select ProxyTest and click Add Selected Items to move it to the Selected column. ProxyTest should be the only item in the selected column.

    • Section Name: Enter ProxyTest in the field.

    • Element Name: Enter ProxyTest/Tree/Root in the field.

    Figure 44-9 Add New Tree Tab Page

    Description of Figure 44-9 follows
    Description of "Figure 44-9 Add New Tree Tab Page"
  4. Once the fields have been properly entered, click Save to save the asset.
44.3.5.2 Implementing the Tree Code
  1. In ProxyTest/Tree/Root, query the external repository to get the tree root nodes (in this case, the list of categories).
  2. Generate the Tree node data for each category:
    <%@ taglib prefix="cs" uri="futuretense_cs/ftcs1_0.tld"%> 
    <%@ taglib prefix="satellite" uri="futuretense_cs/satellite.tld"%>
    <%@ taglib prefix="ics" uri="futuretense_cs/ics.tld"%> 
    <%@ page import="org.codehaus.jettison.json.*"%>
    <cs:ftcs>
    
    <%-- Retrieve all categories from ProxyTest repository --%>
    <ics:setvar name="serviceURL" value="/browse/categories.json" />
    <ics:callelement element="ProxyTest/GetData" />
    
    <%
    JSONArray list = (JSONArray)ics.GetObj("items");
    for (int i = 0; i < list.length(); i++) {
         String category = (String)list.get(i);
         // 1) build a tree node id - needs to be unique
         // Note: we need to make sure that AssetType is not present in the scope
         // (BuildTreeNodeID is otherwise assuming the tree node to be an asset node)
         %>
         <ics:removevar name="AssetType" />
         <ics:callelement element="OpenMarket/Gator/UIFramework/BuildTreeNodeID" >
              <ics:argument name="AdHoc" value='<%=category %>' />
         </ics:callelement>
         <%
         // 2) build the 'LoadURL' that is, the URL to call to load this node's children
         // OpenMarket/Gator/UIFramework/LoadTab is a standard element. 
         // Required input is:
         // - populate: the element rendering tree nodes to execute
         // - op: must be set to 'load'
         //
         // We're also passing 'category' which is required by our custom logic in 
         // ProxyTest/Tree/Load
         //
         %>
         <satellite:link assembler="query"
                           pagename="OpenMarket/Gator/UIFramework/LoadTab"
                           outstring="LoadURL">
         <satellite:argument name="populate" value="ProxyTest/Tree/Load"/>
         <satellite:argument name="op" value="load"/> 
         <satellite:argument name="category" value='<%=category %>' />
         </satellite:link>
    
         <ics:callelement element="OpenMarket/Gator/UIFramework/BuildTreeNode">
              <ics:argument name="Label" value='<%=category %>' />
         </ics:callelement>
    <%}%>
    </cs:ftcs>
    

    This figure shows the tree generated with this code:

    Figure 44-10 Generated Custom Tree

    Description of Figure 44-10 follows
    Description of "Figure 44-10 Generated Custom Tree"

    Note:

    The elements OpenMarket/Gator/UIFramework/BuildTreeNodeID and OpenMarket/Gator/UIFramework/BuildTreeNode both consume variables in the ICS scope. Since the <ics:callelement /> tag has a global scope, it is, in some cases, necessary to explicitly remove (permanently or temporarily) certain variables from the ICS scope, using <ics:removevar />.

  3. In ProxyTest/Tree/Load, query the external service to retrieve all content in a given category, then render a node for each content item:
    <%@ taglib prefix="cs" uri="futuretense_cs/ftcs1_0.tld"%> 
    <%@ taglib prefix="ics" uri="futuretense_cs/ics.tld"%> 
    <%@ taglib prefix="proxy" uri="futuretense_cs/proxy.tld"%> 
    <%@ page import="org.codehaus.jettison.json.*"%>
    <cs:ftcs>
    
    <%-- Retrieve all content for a given category --%>
    <ics:setvar name="serviceURL" value='<%="/browse/" + ics.GetVar("category") +
       ".json"%>' />
    <ics:callelement element="ProxyTest/GetData" />
    
    <%
    JSONArray list = (JSONArray)ics.GetObj("items");
    
    for (int i = 0; i < list.length(); i++) {
         JSONObject item = (JSONObject)list.get(i);%>
    
         <proxy:register externalid='<%=item.getString("id") %>'
                         type="ProxyTest"
                         name='<%=item.getString("title") %>'
                         varname="internalid" />
    
         <ics:callelement element="OpenMarket/Gator/UIFramework/BuildTreeNodeID">
            <ics:argument name="AssetType" value="ProxyTest" />
            <ics:argument name="ID" value='<%=ics.GetVar("internalid") %>' />
         </ics:callelement>
    
         <ics:callelement element="OpenMarket/Gator/UIFramework/BuildTreeNode">
            <ics:argument name="Label" value='<%=item.getString("title") %>' />
            <ics:argument name="Description" value='<%=item.getString("title") %>' />
            <ics:argument name="executeFunction" value="inspect" />
         </ics:callelement>
         <%
    }
    %>
    </cs:ftcs>
    

    You then should be able to browse each category.

    Figure 44-11 Browsing Custom Tree Objects

    Description of Figure 44-11 follows
    Description of "Figure 44-11 Browsing Custom Tree Objects"
  4. Double-click a node to open the default proxy asset inspection page for that node.

44.4 Setting Up YouTube Proxy Assets

To access YouTube proxy assets, you need to add an API key and set up a proxy server or WebLogic Server– if your WebCenter Sites instance is installed on WebLogic Server.

To set up YouTube proxy assets:
  1. Obtain the Google Developers YouTube API key:
    1. Register your project in the Google Developers Console.
    2. Enable the YouTube Data API v3.
    3. Generate a public API server key.
  2. Copy the generated key into the properties file:
    1. Open the wcs_properties.json file.
    2. Search for the wcsites.youtube.api.key key, and add the generated API key into the value:
      {
      "key" : "wcsites.youtube.api.key",
      "value" : "AIzaSyBnYqexNhlvU6QaJ2emS829bF...",
      "valid_values" : [ "" ],
      "defaultValue" : "",
      "category" : "Core",
      "subcategory" : "",
      "global" : true,
      "localServerValues" : { },
      "hide" : false,
      "readonly" : false,
      "restart_required" : false,
      "deprecated" : false,
      "description" : "YouTube public API access key used to search Youtube videos (proxy assets). Created by registering project in the Google Developers Console, enabling YouTube Data API v3, and generating a public API server key."
      }
  3. Search and use the YouTube proxy asset that make use of the YouTube API v3:
    1. Switch to the avisports site.
    2. Go to the Contributor interface.
    3. In the Search bar, set the search type as YouTube Video.
    4. Enter a search term and click the Search icon.
      YouTube videos are displayed.
  4. If you are using a proxy server, follow these steps to configure it for YouTube proxy assets:
    1. In Sites Explorer, navigate to Tables > ElementCatalog > CustomElements > YouTube > UI > Data > Search.
    2. Edit the row for SearchAction.jsp.
      • In the resdetails1 column, enter the proxy host. For example, proxyHost=my-proxy.company.com.

      • In the resdetails2 column, enter the proxy port. For example, proxyPort=80.

  5. If you are using the WebLogic Server on which WebCenter Sites is installed, follow these steps to configure the WebLogic Server for YouTube proxy assets:
    1. Open the Admin console: host:admin port/console.
    2. Expand Domain Structure, then Environment, and then Servers.
    3. Click the managed server on whichWebCenter Sites is running.
    4. Under the SSL tab, expand Advanced.
      • Under Hostname Verification, select Custom Hostname Verifier.

      • For Custom Hostname Verifier, enter weblogic.security.utils.SSLWLSWildcardHostnameVerifier.

    5. Ensure that the WebLogic server’s truststore trusts googleapis.com. WebLogic's default settings allow this:
      • Under the Keystores tab, for Keystores, click Change, and select Demo Identity and Demo Trust.

      • Under the Keystores tab, ensure that the passphrase contains the Java Standard Trust Keystore (default is changeit).

  6. Restart the server.

44.5 User Interface Customizations

You can make WebCenter Sites an enjoyable experience for contributors and marketers if you customize the Contributor interface in ways that make the common tasks easier. For instance, you may want to customize search to help them search content faster.

This topic describes customizable portions of the interface to synchronize with third-party software.

44.5.1 Customizing the Search Start Menu

In the Contributor interface, users run searches restricted to a specific asset type by selecting a Search start menu. This figure shows the Search Type list:

Figure 44-12 Search Type Start Menu Selection

Description of Figure 44-12 follows
Description of "Figure 44-12 Search Type Start Menu Selection"

To customize search for a given asset type, override the controller element UI/Data/Search/Search by creating the following elements:

CustomElements/<AssetType>/UI/Data/Search/SearchAction
CustomElements/<AssetType>/UI/Data/Search/SearchJson

For more details about controller elements and element overrides, see Customizing Search Views of the Contributor Interface.

UI/Data/Search/Search runs the search code and generates the appropriate JSON data for the grid widget's consumption (whether in list or thumbnail view, docked or undocked). The JSON data must be a valid Dojo datastore. For an implementation example, see Customizing the Content Tree.

44.5.2 Customizing the Content Tree

The content tree can be customized by defining a custom tree section, contained in a new or existing tree tab: For more details about defining custom tree tab sections, see Options for Managing Access to the Tree (Admin Interface Only).

A custom tree tab section points to a JSP element generating data based on some rendering logic, eventually consumed by the tree widget. Tree data is generated using the following utility elements:

  • OpenMarket/Gator/UIFramework/BuildTreeNodeId: Generates a tree node ID.

  • OpenMarket/Gator/UIFramework/BuildTreeNode: Generates properly formatted tree node data.

The following examples show how to build a tree node, whether it represents an asset or not (that is, an asset node compared to an adhoc node). See Customizing the Tree in the Admin Interface.

Example 1: Build a Tree Node Representing an Asset

This example shows how to generate a tree node representing a single asset node. The node runs the inspect action when double-clicked (see executeFunction parameter); that is, the asset default inspect view is rendered in a new tab (or focused if the asset is opened in a tab).

<%--
- Generates a tree node id.
- The element expects the asset id and type to be passed in parameters
- called respectively "ID" and "AssetType".
- The generated id is stored in a WebCenter Sites variable called "TreeNodeID"
--%>
<ics:callelement element="OpenMarket/Gator/UIFramework/BuildTreeNodeID">
     <ics:argument name="AssetType" value="Article" />
     <ics:argument name="ID" value="1234567890" />
</ics:callelement>

<%-- 
- Generates a tree node for this asset.
- Note that this element implicitly consumes variables
- currently present in the ICS scope, including "TreeNodeID"
--%>
<ics:callelement element="OpenMarket/Gator/UIFramework/BuildTreeNode">
     <ics:argument name="Label" value="Node Label, for example asset name or other
                   readable string" />
     <ics:argument name="Description" value="Some optional tooltip text" />
     <ics:argument name="executeFunction" value="inspect" />
</ics:callelement>

Example 2: Build an adhoc Tree Node

Tree nodes do not necessarily represent assets, in which case they are called adhoc nodes. This example shows how to generate an adhoc node representing a parent node, a node that has children and can be expanded and collapsed.

<%--
- Generates a tree node id. 
- For adhoc nodes, the expected parameter is called "AdHoc",
- and can be any arbitrary string, which must be unique across tree nodes
--%>
<ics:callelement element="OpenMarket/Gator/UIFramework/BuildTreeNodeID" >
  <ics:argument name="AdHoc" value="SomeUniqueString" />
</ics:callelement>

<%-- 
- Generates a "LoadURL", that is the URL to be called when a tree node
- is expanded. In this case, we're calling the default utility SiteCatalog entry
- (OpenMarket/Gator/UIFramework/LoadTab) which, in turn, will invoke
- a custom element ("Some/Other/Element" in our example), in charge
- of generating the child nodes, based on some custom logic.
--%>
<satellite:link
       assembler="query" 
       pagename="OpenMarket/Gator/UIFramework/LoadTab"
       outstring="LoadURL">
  <satellite:argument name="populate" value="Some/Other/Element"/>
  <satellite:argument name="op" value="load"/>
</satellite:link>

<%--
- Generates the corresponding tree node data
- Note that this element consumes the "LoadURL" variable previously generated.
- The presence of LoadURL indicates whether a node should be marked as expandable
or not.
--%>
<ics:callelement element="OpenMarket/Gator/UIFramework/BuildTreeNode">
  <ics:argument name="Label" value="Some meaningful node label" />
</ics:callelement>

44.6 Information About Embedding Proxy Assets in Web Pages

You can define templates for proxy assets to make them appealing on the website and embed proxy assets inside pages.

Topics:

44.6.1 Writing a Template for Proxy Assets

Templates can be defined for proxy assets, just as templates can be defined for any other asset type.

Using a Template to Render Proxy Assets:
  1. In the Admin interface, click New on the menu bar and then choose New Template.
    The Template form is displayed.
  2. In the Name field, enter ProxyTestSummary.
  3. From the For Asset Type drop-down list, choose ProxyTest.
  4. In the Applied to subtypes box, choose Any, if not selected already.
  5. On the Element tab:
    • From the Usage drop-down list, choose Element is used as Layout.
    • In the Create Template Element? section, click JSP .
    • In the Element Logic box, enter the following code from ${WCS_PROXY}\templates\ProxyTestSummary.jsp:
    <%@ taglib prefix="cs" uri="futuretense_cs/ftcs1_0.tld"
    %><%@ taglib prefix="ics" uri="futuretense_cs/ics.tld"
    %><%@ taglib prefix="render" uri="futuretense_cs/render.tld"
    %><%@ taglib prefix="fragment" uri="futuretense_cs/fragment.tld"
    %><%@ page import="javax.ws.rs.client.*"
    %><%@ page import="javax.ws.rs.core.*"
    %><%@ page import="org.codehaus.jettison.json.*"
    ><%@ page import="com.fatwire.cs.ui.framework.UIException"
    %><%@ taglib prefix="asset" uri="futuretense_cs/asset.tld"%> 
    
    <cs:ftcs>
    <%-- ProxyTest/ProxyTestSummary	--%>
    
    <%-- Record dependencies for the Template --%>
    <ics:if condition='<%=ics.GetVar("tid")!=null%>'>
         <ics:then><render:logdep cid='<%=ics.GetVar("tid")%>' c="Template"/>
         </ics:then>
    </ics:if>
    
    <%-- Set the urlPath to proxy_samples --%>
    <%
    String host = request.getServerName();
    String port = Integer.toString(request.getServerPort());
    String contextPath = request.getContextPath();
    String urlPath = "http://"+host+":"+port+"/"+contextPath+"/proxy_samples/content/";
    %>
    
    <%-- first, retrieve the external id --%>
    <asset:load name="asset" type='<%=ics.GetVar("c") %>'
           objectid='<%=ics.GetVar("cid") %>' />
    <asset:get name="asset" field="name" />
    <asset:get name="asset" field="externalid" />
    
    <%
    // given the external content id, invoke the  third-party repository API
    // to retrieve content metadata
    Client client = ClientBuilder.newClient();
    Response resp = null;
    WebTarget res = null;
    
    try {
         res = client.target(urlPath + ics.GetVar("externalid") + ".json");
         resp = res.request(MediaType.APPLICATION_JSON).get();
    } catch (Exception e) {
         // propagate exception to client-side
         request.setAttribute(UIException._UI_EXCEPTION_, e);
         e.printStackTrace();
         throw e;
    }
    
    String jsonString = resp.readEntity(String.class);
    JSONObject data = new JSONObject(jsonString);
    %>
    
    <%-- finally render content --%>
    <h4><%=data.getString("title") %></h4>
    <p><%=data.getString("foo") %></p>
    <img src="<%=data.getString("image") %>" alt="<%=data.getString("title") %>" />
    
    </cs:ftcs>
    
  6. In the Contributor interface, search for ProxyTest assets while leaving the Search field blank.
  7. Click a ProxyTest asset that includes asset details (for example, YellowSkier).
  8. Click Preview , then choose the ProxyTestSummary layout, and then click Apply.
Title, metadata, and image of the ProxyTest asset should be displayed.This image shows a sample graphic called YellowSkier.

44.6.2 Using Proxy Assets in Slots

Proxy assets can be embedded inside pages using the exact same tags and principles that apply to standard assets.

  1. Create a Page attribute:
    1. In the Name field, enter ProxyTestAttribute.
    2. From the Attribute Type drop-down list, choose asset.
    3. From the Asset Type drop-down list, choose ProxyTest.
    4. Click the Save icon.
  2. Create a Page definition:
    1. In the Name field, enter ProxyTestPageDef.
    2. In the Attributes section, select the ProxyTest attribute and then click Optional.
    3. Click the Save icon.
  3. Create a template for the Page asset:
    1. In the Name field, enter ProxyTestSlotTemplate.
    2. From the For Asset Type drop-down list, choose Page.
    3. In the Applied to subtypes box, choose Any, if not selected already.
    4. On the Element tab:
      • From the Usage drop-down list, choose Element is used as Layout.

      • In the Create Template Element? section, click JSP .

      • In the Element Logic box, enter the following code from ${WCS_PROXY}\templates\ProxyTestSlotTemplate.jsp
        <%@ taglib prefix="cs" uri="futuretense_cs/ftcs1_0.tld"%>
        <%@ taglib prefix="ics" uri="futuretense_cs/ics.tld"%>
        <%@ taglib prefix="render" uri="futuretense_cs/render.tld"%>
        <%@ taglib prefix="insite" uri="futuretense_cs/insite.tld"%>
        <%@ taglib prefix="assetset" uri="futuretense_cs/assetset.tld"%>
        <cs:ftcs><render:logdep cid='<%=ics.GetVar("tid")%>' c="Template"/>
        <html>
        <head>
             <title>ProxyTest Slots Example</title>
        </head>
        <body>
             <assetset:setasset name="page" id='<%=ics.GetVar("cid") %>'
                                type='<%=ics.GetVar("c") %>' />
             <assetset:getattributevalues attribute="ProxyTestAttribute" listvarname="ProxyTest"
                                name="page" typename="PageAttribute" />
             <ics:listget listname="ProxyTest" fieldname="value" output="id" />
             <h3>ProxyTest Slots Example</h3>
             <insite:calltemplate field="ProxyTestAttribute" c='ProxyTest'
                                cid='<%=ics.GetVar("id") %>' tname="ProxyTestSummary" />
        </body>
        </html>
        </cs:ftcs>
  4. Create the Page asset:
    1. In the Contributor interface, from the menu bar, select ContentNew, and then select Page (Section).
    2. In the Name field, enter ProxyTestPage.
    3. From the Page Definition drop-down list, choose ProxyTestPageDef.
    4. From the Template drop-down list, choose ProxyTestSlotTemplate.
    5. In form mode and web mode, drag and drop ProxyTest assets into the ProxyTestAttribute slot.
      In web mode, the ProxyTest asset is rendered using the ProxyTestSummary template.
This image shows the ProxyTest Slots Example.

44.6.3 About Caching Proxy Assets

Because the rendered content is stored and managed in a separate repository, WebCenter Sites has no way to know when any content is modified, or even if content is modified. Oracle recommends to set cache expiration to a limited period of time on templates rendering proxy assets, such as the Summary template defined in Writing a Template for Proxy Assets.