60 Developing Applications with WEM Framework

You can explore the Articles sample application to understand the basic architecture of an application that makes REST calls.

For information about developing applications with the WEM framework, see these topics:

60.1 About the Articles Sample Application's Structure

In the source directory for the Articles sample application, you will see source files, logger file, installer resources, home page files, and configuration files.

The following figure shows the source structure of the Articles sample application. On deployment, the following directories are copied from source to target: The contents of the lib directory are copied to /WEB-INF/lib/. The contents of the resources directory are copied to /WEB-INF/classes/.

Figure 60-1 Articles Sample Application Source Structure

Description of Figure 60-1 follows
Description of "Figure 60-1 Articles Sample Application Source Structure"

Articles is a Java Web application developed on Spring MVC. The following pages are available:

  • /install.app is the Articles installation page, which also displays a confirmation message when the application is successfully installed.

  • /home.app is the home page of the Articles application.

60.2 About the Articles Sample Application's Configuration Files

The Articles sample application’s configuration files are applicationContext.xml and spring-servlet.xml.

  • applicationContext.xml (in /WEB-INF/) holds SSO and application-specific configurations (such as a predefined user and the site on which to enable the data model and assets).

  • spring-servlet.xml (in /WEB-INF/) is the default Spring configuration file. This file stores the Spring configuration and references the following controllers (described in Source Files):

    • HomeController

    • InstallController

    • LayoutController

    • ProxyController

    • loggingconfig.xml (in /<sitesshared>/config) is the logging configuration file. On application deployment, it is copied from /<sitesshared>/config to webcentersites\sites-home\template\config.

Source Files

/sample app/articles/src/main/java/

The /sample/ folder contains the source files listed below:

  • Configuration.java is populated (by the Spring framework) from the applicationContext.xml file.

  • HomeController.java is the home page controller, which renders a single home page. This controller reads the list of sample articles from the WebCenter Sites platform using the REST API and displays them on the home page.

    The sample articles consist of images and text, stored in /sample app/articles/src/main/resources/install. The sample articles are installed in the WebCenter Sites database by InstallController.java.

  • InstallController.java registers the Articles application, and writes the application's asset model and sample assets to the database.

  • LayoutController.java displays the application's layout page (layout.app) used by the WEM UI framework. LayoutController.java is also used during the application registration procedure.

  • ProxyController.java delegates AJAX requests to the WebCenter Sites REST servlet.

  • TldUtil.java utility class contains TLD function implementations.

Installer Resources

/sample app/articles/src/main/resources/install

The /install/ folder contains the following resources, used by the InstallController to construct the home page (Figure 60-3):

  • strategies.png

  • strategies.txt

  • tips.png

  • tips.txt

Home Page Files

/sample app/articles/src/main/webapp/images

The /images/ folder contains:

  • articles.png icon (Figure 60-2), which represents the Articles application in the applications bar

  • In Figure 60-3:

    • edit.png is the icon for the Edit function

    • save.png is the icon for the Save function

    • cancel.png is the icon for the Cancel function

Scripts

/sample app/articles/src/main/webapp/scripts

The /scripts/ folder contains the json2.js utility script, used to convert strings to and from JSON objects.

Styles

/sample app/articles/src/main/webapp/styles

The /styles/ folder contains main.css, which specifies CSS styles used by this Web application.

Views

/sample app/articles/src/main/WEB-INF/jsp

The /jsp/ folder contains:

  • home.jsp, which is used to render the home page view of the Articles application (Figure 60-3).

  • layout.jsp, which defines the application layout.

WEB-INF

/sample app/articles/src/main/WEB-INF

The /WEB-INF/ folder contains:

60.3 Making REST Calls

WebCenter Sites REST resources support two types of input and output formats: XML and JSON. If you would like to get specific return formats, use HTTP headers that specify the MIME type application/xml or application/json.

For example, when specifying input format to be XML, set Content-Type to application/xml. When specifying the output format, set Accept (the expected format) to application/xml. If other output formats are specified, they are ignored. The default is XML, if not specified in Content-Type or Accept (for sample code, see Making REST Calls from JavaScript).

Topics:

60.3.1 Making REST Calls from JavaScript

  • Use the following code (in home.jsp) to perform AJAX calls to the asset REST services to save asset data. Note that the request is actually performed to the proxy controller which redirects the request to the destination REST service.

    Note:

    We use the JSON stringify library to serialize a JavaScript object as a string. It is much more convenient to write JSON objects instead of strings.

    // Form the URL pointing to the asset service 
    // to the proxy controller, which will redirect this request to the CS REST servlet.
    var idarr = assetId.split(":");
    var assetUrl = "${pageContext.request.contextPath}/REST/sites/${config.csSiteName}/types/" + idarr[0] + "/assets/" + idarr[1];
    
    // For the data object to be posted.
    var data = 
    {
     "attribute" : 
    [
    {
       "name" : "source",
      "data" : 
     {
        "stringValue" : document.getElementById("source_e_" + assetId).value
    }
    },
    {
      "name" : "cat",
     "data" : 
     {
    "stringValue" : document.getElementById("cat_e_" + assetId).value
    }
    }
    ],
     "name" : document.getElementById("name_e_" + assetId).value,
     "description" : document.getElementById("desc_e_" + assetId).value,
     // This should be removed.
     "publist" : "${config.csSiteName}"
    };
    // Convert JSON data to string.
    var strdata = JSON.stringify(data);      
      
    // Perform AJAX request.
    var req = getXmlHttpObject();       
    req.onreadystatechange = function ()
    {
    if (req.readyState == 4)
    {
    if (req.status == 200)
     {
     // On successful result
    // update the view controls with new values and switch the mode to 'view'.
      for (c in controls)
    {
    document.getElementById(controls[c] + "_v_" + assetId).innerHTML = 
    document.getElementById(controls[c] + "_e_" + assetId).value;
    }  
    switchMode(assetId, false);
    }
    else
    {
    // Error happened or the session timed out,
    // reload the current page to re-acquire the session. 
    alert("Failed to call " + assetUrl + ", " + req.status + " " + req.statusText);
    window.location.reload( false );
    }
    }
    };
    // We put Content-Type and Accept headers
    // to tell CS REST API which format we are posting
    // and which one we are expecting to get.
    req.open("POST", assetUrl, true);
    req.setRequestHeader("Content-Type", "application/json;charset=utf-8");
    req.setRequestHeader("Content-Length", strdata.length);
    req.setRequestHeader("Accept", "application/json");
    req.send(strdata);
    }
    

60.3.2 Making REST Calls from Java

  • Use the code below (in HomeController.java) to call the assets search service to list all assets of type FW_Article. The code uses the Jersey Client library passing objects from the rest-api-<version>.jar library provided by the WEM Framework. This leverages strong typing in Java.

    It is important to note that a token must be acquired from Java code by calling the SSOAssertion.get().createToken() method. It is unnecessary to do so in JavaScript as that side is authenticated against WEM SSO.

    // Use Jersey client to query CS assets.
    Client client = Client.create();
    String url = config.getRestUrl() + "/types/FW_Article/search";
    WebResource res = client.resource( url );
                    
    // Construct URL and add token (for authentication purposes)
    // and fields (specify which fields to retrieve back) parameters.        
    res = res.queryParam("fields", URLEncoder.encode("name,description,content,cat,source", "UTF-8"));
    res = res.queryParam("ticket", SSO.getSSOSession().getTicket(res.getURI().toString(), config.getCsUsername(), config.getCsPassword()));
    // Put Pragma: auth-redirect=false to avoid redirects to the CAS login page.
    Builder bld = res.header("Pragma", "auth-redirect=false");
            
    // Make a network call.
    AssetsBean assets = bld.get(AssetsBean.class);
    

    Note:

    The custom Pragma: auth-redirect=false header instructs the CAS SSO filter not to redirect to the CAS sign-in page, but to return a 403 error instead, when no ticket is supplied or the supplied ticket is invalid.

60.4 Constructing URLs to Serve Binary Data

For the Articles application, you can leverage the Blob server in WebCenter Sites to serve BLOB data. You can use the getBlobUrl function to construct a URL pointing to the binary data for a given attribute in a given asset.

  • blobUrl points to the Blob server (http://localhost:8080/cs/BlobServer by default.

    public String getBlobUrl(String assetType, String assetId, String attrName, String contentType)
    throws Exception
    {
    String contentTypeEnc = URLEncoder.encode(contentType, "UTF-8");
            
    return blobUrl + "?" +
    "blobkey=id" + 
    "&blobnocache=true" +
    "&blobcol=thumbnail" +
    "&blobwhere=" + assetId +
    "&blobtable=" + assetType +
    "&blobheader=" + contentTypeEnc +
    "&blobheadername1=content-type" +
    "&blobheadervalue1=" + contentTypeEnc;
        }
    
  • Alternatively, to get binary data, load an asset using the resource /sites/{sitename}/types/{assettype}/assets/{id}. When loaded, the asset contains the URL pointing to the BLOB server.

60.5 Accessing Parameters from the WEM Framework

With the WemContext JavaScript Context object, you can empower applications to find out which user has logged in to which site. You can also enable applications to share data.

The UI container provides a JavaScript Context object (WemContext) to all applications inside the container. The Context object is used by the applications to get details from the WEM Framework about the logged-in user and site (typically, to get the current site's name from the UI container). The Context object also provides various utility methods that the applications use to share data. The Context Object can be used by applications running in the same domain as WebCenter Sites or in different domains.

Note:

The wemcontext.html file lists the exposed methods, summarized in Methods Available in Context Object.

Topics:

60.5.1 Initializing and Using Context Object in the Same Domain

To initialize and use Context Object for applications in the WebCenter Sites domain:

  1. Include wemcontext.js.
  2. Retrieve an instance of the WemContext object.
  3. Use the methods of WemContext.
<script src='http://<csinstalldomain>/<contextpath>/wemresources/js/WemContext.js'></script>
<script type="text/javascript">
var wemContext = WemContext.getInstance(); // Instantiate Context Object
var siteName = wemContext.getSiteName(); // Get Site Name
var userName = wemContext.getUserName(); // Get UserName
</script>

60.5.2 Initializing and Using Context Object for Cross-Domain Applications

To initialize and use Context Object for cross-domain applications:

  1. Copy wemxdm.js, json2.js, and hash.html (from the Misc/Samples folder) to your application.
  2. Open the sample.html file and make the following changes to perform cross-domain calls:
    • Change the paths of wemxdm.js and json.js and hash.html to their paths in the application (see the example after step d).

    • Change the path of wemcontext.html to its location in WebCenter Sites . (wemcontext.html is located under /wemresources/wemcontext.html. Use the WebCenter Sites host name and context path.)

    • In the interface declaration, specify methods to be used in the framework.

    • Implement those methods in the local scope and invoke the remote method.

<script type="text/javascript" src="../js/wemxdm.js"></script>
<script type="text/javascript">
//  Request the use of the JSON object
WemXDM.ImportJSON("../js/json2.js");
var remote;
window.onload = function() {
// When the window is finished loading start setting up the interface
remote = WemXDM.Interface(/** The channel configuration */
{
// Register the url to hash.html.
local: "../hash.html",
// Register the url to the remote interface
remote: "http://localhost:8080/cs/wemresources/wemcontext.html"
}, /** The interface configuration */
{
remote: {
getSiteName :{},
...

}
},/**The onReady handler*/ function(){
// This function will be loaded as soon as the page is loaded
populateAttributes();
});
}
</script>

<script type="text/javascript"> 
/** Define local methods for accessing remote methods  */
function getSiteName(){
remote.getSiteName(function(result){
alert("result = " + result);
});
}
 ... 
</script> 

60.5.3 Methods Available in Context Object

The following table lists and describes the methods available in Context Object.

Table 60-1 Methods Available in Context Object

Return Type Method name and Description

Object

getAttribute(attributename)

Returns attribute value for the given attribute name.

Object

getAttributeNames()

Returns all the attribute names.

Object

getCookie(name)

Returns cookie value for the given name. It has all restrictions of the normal browser cookie.

Object

getCookies()

Returns all the cookies.

Object

getLocale()

Returns locale.

Object

getSiteId()

Returns the site ID.

Object

getSiteName()

Returns the site name.

Object

getUser()

Returns user object.

Object

getUserName()

Returns user name.

void

removeCookie(name, properties)

Removes cookie.

void

setAttribute(attributename, attributevalue)

Sets attribute. These attributes can be accessed in other applications.

void

setCookie(name,value,expiredays,properties)

Sets the cookie.

60.6 Registering Applications with Different Views

In WEM Framework, when you register an application to expose it, an asset of type FW_Application and another of type FW_View are created for each view associated with the application. These asset types are enabled on AdminSite.

Their attributes are defined in the Oracle Fusion Middleware Java API Reference for Oracle WebCenter Sites. Programmatic registration is the preferred method. For an example of manual registration, see Registering Applications Manually in WEM Framework.

Topics:

60.6.1 Registering Applications with an iframe View

The section uses code from the Articles sample application to illustrate the registration process. Articles has a single view of type iframe. The same steps apply to JavaScript and HTML views.

To register an application:

  1. Create or get an icon to represent your application. (The icon is displayed in the applications bar.)

    (The Articles sample application uses the articles.png image file located in: /sample app/articles/src/main/webapp/images/)

  2. Create a file that specifies the layout of the application in HTML, that is, for each view, create a placeholder element to hold the content rendered by the view. Applications and views are related as shown in the next figure.

    For example, layout.jsp for the Articles sample application contains the following line:

    <div id="articles" style="float:left;height:100%;width:100%" class="wemholder"></div>

    The view's content is rendered within the placeholder element when the application is displayed (layout.app renders the application's layout; home.app renders the view).

    Note:

    When creating the layout file, specify a unique id for the placeholder element. Specify the same id for the parentnode attribute when coding the view object. Use class="wemholder" for the placeholder elements.

    Figure 60-4 Applications and Views

    Description of Figure 60-4 follows
    Description of "Figure 60-4 Applications and Views "

    The relationship between applications and views is many-to-many. One application can have multiple views and each view can be used by many applications. Only registered views can be shared (through their asset IDs). The view is created within the context of its application if the asset ID is omitted. In the basic case, an application has only one view associated with it.

  3. Invoke the PUT wem/applications/{applicationid} REST service and specify your application bean.
  4. Populate the bean with the view asset and application asset.

    For an iframe view, use the code of the Articles sample application, that is, InstallController.java (locate the comment lines // Create a new view object and // Create a new application object). Set the layouturl attribute to specify the URL of the application's layout page.

    In the Articles application, the layouturl attribute points to the URL of layout.app (implemented by LayoutController.java):

    app.setLayouturl(config.getArticlesUrl() + "/layout.app");
    
  5. To test the results of your registration process, log in to the WEM Admin interface as a general administrator and select Apps on the menu bar. Your application should be listed on that page.

60.6.2 Registering Applications with JavaScript and HTML Views

For applications that use HTML and JavaScript views, follow the steps in Registering Applications with an iframe View, but use the sample code and attributes listed in the following sections:

60.6.2.1 Rendering JavaScript View

Note:

JavaScript specified in the view is rendered (executed) when the application is rendered. Ensure the JavaScript does not conflict with other views.

Sample code:

   window.onload = function () { 
      if (GBrowserIsCompatible()) { 
        var map = new GMap2(document.getElementById("map_canvas")); 
        map.setCenter(new GLatLng(37.4419, -122.1419), 13); 
        map.setUIToDefault(); 
      } 
   }
  • Rendering the JavaScript view from a source URL

    Set the following attributes:

    • name: Name of the view

    • parentnode: ID of the placeholder element (from step 2 in Registering Applications with an iframe View)

    • viewtype: fw.wem.framework.ScriptRenderer, which renders JavaScript into the placeholder element

    • sourceurl: Path of the .js file, which provides content for the view. For example: http://example.com:8080/js/drawTree.js

  • Rendering the JavaScript view from source code

    Set the following attributes:

    • name: Name of the view

    • parentnode: ID of the placeholder element (from step 2 in Registering Applications with an iframe View)

    • viewtype: fw.wem.framework.ScriptRenderer, which renders JavaScript into the placeholder element

    • javascriptcontent: JavaScript code (sample provided above). The code must not contain <script> tags.

60.6.2.2 Rendering HTML View

Note:

HTML specified in the view is rendered (executed) when the application is rendered.

Sample code:

<object width="480" height="385">
 <param name="movie" value="http://www.localhost:8080/jspx/flash_slider_main.swf"></param>
 <param name="allowFullScreen" value="true"></param>
 <embed src=" http://www.localhost:8080/jspx/flash_slider_main.swf"
  type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true"
  width="480" height="385">
 </embed>
</object>
  • Rendering the HTML view from a source URL

    Set the following attributes:

    • name: Name of the view

    • parentnode: ID of the placeholder element (from step 2 in Registering Applications with an iframe View)

    • viewtype: fw.wem.framework.IncludeRenderer, which renders JavaScript into the placeholder element

    • sourceurl: Path to the HTML file that provides content for the view. For example: http://example.com:8080/js/drawTree.jsp.

  • Rendering the HTML view from source code

    Set the following attributes:

    • view: Name of the view

    • parentnode: ID of the placeholder element (from step 2 in Registering Applications with an iframe View)

    • viewtype: fw.wem.framework.IncludeRenderer, which renders JavaScript into the placeholder element

    • includecontent: HTML content (sample provided above. The code must not contain <html> or <body> tags.