Marrying the Worlds of ADF and HTML 5

Version 9

    The adoption of HTML5 by all major browsers, including those on mobile devices, is catalyzing a new way of developing and architecting web applications. Rich client applications, in combination with fairly thin server sides, leverage JavaScript for what it is worth, providing a rich, interactive and smooth user experience. Frameworks such as AngularJS bring Model View controller (MVC)-style structure to these client applications.

     

    Enterprise application frameworks like Oracle Application Development Framework (ADF) also make use of the new opportunities offered by HTML5. Notable examples include the rich data visualization library (DVT) and the support for tablet devices. At the same time, the architecture paradigm for these applications is more focused on the server side.

     

    This article demonstrates how, within the context of an ADF (or WebCenter Portal) application, even developers with no ADF skills at all can integrate small or large components developed with AngularJS outside of the ADF application. The rich client component—in this case, a tagcloud—receives data from the ADF application and exchanges events with it. The component is wrapped in an ADF taskflow and thus becomes easily (re)usable for ADF developers, who may not have any notion of AngularJS or even JavaScript.

     

    The 2014 FIFA World Cup inspired us to create a sample application that displays the 64 matches played by the 32 countries contending in the tournament. It’s a pure ADF application that shows the matches in a table display that does filtering and sorting. The application’s built-in capabilities can switch styles and change languages, but it’s a bit dull—it could do with some HTML5 spicing up.

     

    We then introduce an HTML5 application created with AngularJS that uses an open source tagcloud component. This stand-alone application is developed with no prior knowledge of ADF and the pending integration. It represents a wide array of such applications that could be developed from scratch or by using the thousands of components available from the developer community.

     

    With the integration of this tagcloud application into the ADF application, tags that are derived automatically from the data on the football matches, as well as those added manually, are shown in the tagcloud. By repeatedly clicking on the tags, the user can zoom in on a subset of the matches, quickly finding matches that have specific tags applied to them. In a special edit mode, the tagcloud component can be used to manipulate the tags for a specific match. Newly applied tags and tag removals are communicated to the ADF application that updates the underlying database.


    jellema-html5-adf-fig01.png

    Figure 1


    In a few steps, we embed the tagcloud application in an ADF taskflow, we wire the taskflow input parameters to the Angular data scope, and we implement an event bridge for mutual exchange between the guest tagcloud component and the host ADF application. Next, we look at leveraging ADF resource bundles, skins and even customization and personalization inside the embedded tagcloud component.


    We will realize an ADF application that is enriched with a pure HTML5, non-ADF Faces component, thus leveraging both the enterprise facilities of ADF (and Fusion Middleware) as well as the lean, rich, single-page, native HTML5 goodness that frameworks and communities such as Angular can provide us with. And the approach we demonstrate in this article is one you can emulate in your own ADF applications, allowing a similar reuse of rich components from a world beyond ADF.

     

    jellema-html5-adf-fig02.png

    Figure 2

     

    Resources

    All sources for the World Cup Match Center sample application can be retrieved from a GitHub repository at:  https://github.com/pavadeli/adf-html5.


    The development of the ADF application prior to the integration of the tagcloud component is described in the article “The Making of the World Cup Football 2014 Match Center Application.” This article provides instructions on setting up an environment for loading, running and further developing this application. It also gives additional details on some of the ADF mechanisms used in the application, such as the resource bundles and skins.


    Details on the standalone AngularJS tagcloud application, as well as on the Angular web development environment are available in the article “Developing the AngularJS Tagcloud Application.” This article explains the tools used—Node.js, Bower, Gulp—and provides references to useful AngularJS resources.


    This presentation on SlideShare provides some additional visualizations: Marrying HTML5 and Angular to ADF - Oracle OpenWorld 2014 Preview.

     

    Both JDeveloper 11g and JDeveloper 12c can be used to develop and run the ADF application discussed in this article. Download them from OTN: http://www.oracle.com/technetwork/developer-tools/jdev/downloads/index.html.


    The Oracle Database to be used for the World Cup schema should be 11g or 12c (the Oracle Database 11gR2 XE edition suffices: http://www.oracle.com/technetwork/database/database-technologies/express-edition/downloads/index.html).


    A complete VM with an environment in which the sample application can be developed can be created using Vagrant and Puppet, as described here: http://technology.amis.nl/2014/07/29/creating-automated-jdeveloper-12-1-3-oracle-xe-11gr2-environment-provisioning-using-vagrant-and-puppet/ .

     

    Rich Client vs. Thick Server

    An important development sparked by HTML5 is the notion of rich-client web applications. Such applications—for example, built with AngularJS—are created in JavaScript and loaded completely into the client (the browser). After this initial load, these applications seek server interaction only to retrieve data or push data to a persistent data store. These applications typically implement a client-side MVC pattern and handle the UI, interactions and navigation, and the management of data exposed through the UI. These applications do not have the notion of a server-side session with associated state. In fact, they may even use client-side storage that allows them to retain local user preferences and perhaps supports a certain degree of off-line usage when the server is temporarily unavailable.


    These applications can easily scale (most of the work is done in the client) and fail-over (their server-side interactions are stateless). Development cycles are quick: just reload the browser. Straightforward data retrieval and manipulation are typically done in JSON through RESTful services. Longer-running transactions and certain security aspects can be a little harder to achieve, because the client is not enough by itself.


    Figure3 demonstrates that there is a range of web application styles, from thick client to thin client, with a varying number of responsibilities implemented in the client or server.

     

    jellema-html5-adf-fig03.png

    Figure 3

     

    Because thick clients leverage the browser capabilities as much as they can, web developers have to be aware of browser differences—something that is usually taken care of by more server-side oriented frameworks such as ADF.


    ADF started its life as a pure server-side framework with very little client-side footprint; JavaServer Faces is architected that way. The partial page refresh feature in ADF (an AJAX implementation) was client-side driven, but server-side implemented. The generation of HTML was done in the server.


    With more recent releases of ADF (11g and 12c), the balance has been shifting. Server-side session state is still an important aspect of ADF, and a scalability inhibitor at middleware level, but the client side has become much more active and almost all of the HTML is created dynamically inside the browser by JavaScript, at run time. This is not so much different from the thick client approach.


    Figure 4 shows how ADF compares to Angular-style applications, on one end, and APEX—obviously, very server oriented—on the other.


    jellema-html5-adf-fig04.png

    Figure 4


    Note how all web applications built on top of the same enterprise resources (databases) can share business services (database packages, web services exposed by a Service Bus or Java application) to a large degree. Even presentation services could potentially be used in both a pure rich-client approach and with an ADF web application.


    The ADF framework insulates developers from many HTML, CSS, JavaScript, HTTP and Java Servlet intricacies, and abstracts away from them the many browser-specific variations. It provides a number of components for data presentation, manipulation and visualization. Through server-side skinning, it handles many browser-specific styling challenges. ADF has a largely browser-independent client-side (JavaScript) API that supports many client-slide actions as well as simple-to-use background [AJAX-style] conversations. It supports development of reusable components. It offers a productive integrated development environment (IDE), JDeveloper, with many wizards, visual editors and reusable building blocks. It can scale to enterprise-level development with many developers and teams. It has some powerful features, such as integrated security, customization and personalization. ADF has started to adopt HTML5 (for example, to replace Flash for data visualizations on tablets) and also supports a degree of responsive design and gesture support to allow ADF applications to be used on tablet devices.


    At the same time, ADF does not yet support many HTML5 features (e.g., Web Sockets, Server Sent Events) and, of course, the widget catalog in ADF does not contain every other user interface component that can be created using HTML5. That is what we will add to ADF: we’ll use modern, rich client web frameworks to introduce some of the HTML5 richness that is not yet available from out-of-the-box ADF and fully embed it in our ADF application. Data, styling, internationalization, personalization and events are provided from the ADF context to the embedded component. The component can manipulate data and publish events of its own that are captured in the ADF components.

     

    The Starter ADF Application: World Cup 2014 Match Center

    The ADF World Cup 2014 Match Center application is a regular ADF application. It contains a model project using ADF Business Components that interact with a simple database schema containing five tables with data on countries, venues and matches. Some advanced SQL is included in two read-only ViewObjects that produce the list of tags for all currently selected matches. This list will be used as the input for the tagcloud component later on.


    The ViewController project contains a single JSPX page—MatchCenter.jspx—that contains a region with a single taskflow. This match taskflow contains a page fragment, matchTable.jsff, with a rich table that lists all matches. This table can be sorted and filtered and manipulated in all the ways the ADF Rich Table component supports. The Javaserver Faces Fragment (JSFF) also binds a simple taglist taskflow that lists a tag collection passed into it as an input parameter in the plainest possible way. The page fragment also contains a popup, which contains another taskflow, match-details. This taskflow presents some details about one specific match, using the matchDetails.jsff page fragment. Among these details is a list of the tags that apply to the match, presented in a second instance of the taglist taskflow.


    jellema-html5-adf-fig05.png

    Figure 5

     

    Note how all web applications built on top of the same enterprise resources (databases) can share business services (database packages, web services exposed by a Service Bus or Java application) to a large degree. Even presentation services could potentially be used in both a pure rich-client approach and with an ADF web application.


    The ADF framework insulates developers from many HTML, CSS, JavaScript, HTTP and Java Servlet intricacies, and abstracts away from them the many browser-specific variations. It provides a number of components for data presentation, manipulation and visualization. Through server-side skinning, it handles many browser-specific styling challenges. ADF has a largely browser-independent client-side (JavaScript) API that supports many client-slide actions as well as simple-to-use background [AJAX-style] conversations. It supports development of reusable components. It offers a productive integrated development environment (IDE), JDeveloper, with many wizards, visual editors and reusable building blocks. It can scale to enterprise-level development with many developers and teams. It has some powerful features, such as integrated security, customization and personalization. ADF has started to adopt HTML5 (for example, to replace Flash for data visualizations on tablets) and also supports a degree of responsive design and gesture support to allow ADF applications to be used on tablet devices.


    At the same time, ADF does not yet support many HTML5 features (e.g., Web Sockets, Server Sent Events) and, of course, the widget catalog in ADF does not contain every other user interface component that can be created using HTML5. That is what we will add to ADF: we’ll use modern, rich client web frameworks to introduce some of the HTML5 richness that is not yet available from out-of-the-box ADF and fully embed it in our ADF application. Data, styling, internationalization, personalization and events are provided from the ADF context to the embedded component. The component can manipulate data and publish events of its own that are captured in the ADF components.

     

    The Starter ADF Application: World Cup 2014 Match Center

    The ADF World Cup 2014 Match Center application is a regular ADF application. It contains a model project using ADF Business Components that interact with a simple database schema containing five tables with data on countries, venues and matches. Some advanced SQL is included in two read-only ViewObjects that produce the list of tags for all currently selected matches. This list will be used as the input for the tagcloud component later on.


    The ViewController project contains a single JSPX page—MatchCenter.jspx—that contains a region with a single taskflow. This match taskflow contains a page fragment, matchTable.jsff, with a rich table that lists all matches. This table can be sorted and filtered and manipulated in all the ways the ADF Rich Table component supports. The Javaserver Faces Fragment (JSFF) also binds a simple taglist taskflow that lists a tag collection passed into it as an input parameter in the plainest possible way. The page fragment also contains a popup, which contains another taskflow, match-details. This taskflow presents some details about one specific match, using the matchDetails.jsff page fragment. Among these details is a list of the tags that apply to the match, presented in a second instance of the taglist taskflow.


    Follow the instructions in the resource “The Making of the World Cup Football 2014 Match Center Application” to set up the development environment with JDeveloper and Database. The web application can be started by running the MatchCenter.jspx page (which will cause the application to be deployed to the Integrated WebLogic Server). Alternatively, you can deploy the application to a stand-alone WebLogic Server; it can then be accessed at http://host:port/WorldCup2014_MatchCenter-step1/faces/MatchCenter.jspx.


    jellema-html5-adf-fig06.png

    Figure 6


    Take a quick spin with the table—sorting and filtering, for example—and open the popup for one or two matches to verify that the taglist for the match is shown in the popup. Try out the skin selector and the language selector in the upper right-hand corner to see their effect on the look and feel. Having the tags is not very useful right now. What we should have is a fancy, rich tagcloud component that brings the tags to life.


    “The Making of the World Cup Football 2014 Match Center Application” describes how the application has been constructed.


    The Starter AngularJS Application: Tagcloud

    A little internet research quickly led to an interesting tagcloud component: http://www.goat1000.com/tagcanvas.php.


    jellema-html5-adf-fig07.png

    Figure 7


    Using this component, we assembled an AngularJS application, as described in “Developing the AngularJS Tagcloud Application.” As Angular applications go, this is a really simple one. But it does demonstrate several of the aspects that have made AngularJS such a popular and successful framework, including the modular structure, the data binding to Plain Old JavaScript objects (POJOs), dependency injection, and the use of simple HTML that is subtly extended to carry attributes that Angular can interpret.


    jellema-html5-adf-fig08.png

    Figure 8


    The development is done using a set of powerful tools that, ideally, you should set up in order to see the application in action, and also to see the quick development iterations that can be achieved. You have to install Node.js (http://nodejs.org/) on your development machine. This tool contains the Node.js Package Manager (NPM), which somewhat resembles the RPM tool in some Linux distributions. Using NPM you will fetch Gulp, a build tool that does for JavaScript what Ant does for Java development. Additionally, NPM is used to install Bower, a tool for dependency management, similar to Maven for Java EE development.


    Our tagcloud application comes with a number of configuration files that tell Bower about its dependencies—especially the one on the AngularJS run-time framework. When all dependencies are dealt with, the application can be run using the Gulp tool, which runs like a web server that serves resources to your local browser (typically, the Google Chrome browser). Gulp is configured with the browser-synch plugin, which makes it automatically refresh the browser upon any change in the application’s sources. That is one of the aspects that makes development so smooth.  


    “Developing the AngularJS Tagcloud Application” provides detailed instructions for setting up the environment and running the application in the html-step1 folder. It is the first step towards the embedded tagcloud application, illustrated by the previous figure. The Angular application is defined largely in the file tagcloud-html.html through a small section of HTML that includes our tag (<tag-cloud>); it will be processed by the tagcloud module that is referenced by the main myApp module and replaced with the actual tagcloud component.

    You may want to change the list of tags defined in the tagcloud-html.html file. After saving, verify in the browser that Gulp has pushed in the change.

     

    Introduction of the Bridge

    Our first step was successful, but still simplistic. We want to be able to use multiple tagclouds—guests—in a single page, without having these tagclouds interfering with each other. And we want to be able to pass events to each of these tagcloud instances and have them pass back events to their host container in the page.


    The following illustration describes the next stage of the Angular tagcloud application, which you will find in the html-step2 folder of the sources for this article. A detailed explanation is available in “Developing the AngularJS Tagcloud Application.” In essence, what has been added in this second step is the OTNBridge component, which is used to create bridges between a host technology and one or more guest technologies on one page, minimizing the amount of knowledge one needs of the other.


    Every bridge created with OTNBridge is responsible for all communication between the host and guest components in a distinct part of the application (page). On creation of a bridge, the host can provide a callback function that will be used to receive messages from guest components in this part of the page. The host can also use this bridge to send messages to individual guest components using their unique IDs. The guest components are required to register themselves at the bridge with this unique ID. To support reusable taskflows later on, the OTNBridge is designed to allow multiple bridges on a single page. In the case of the tagcloud-bridge.html page, there are two div containers that will have a corresponding bridge (created in JavaScript code on the same page):



    On creation of the bridges, a simple callback function is provided to show a browser alert every time a message is received from one of the guest components.


    Both these divs contain exactly the same div container with a guest-component attribute: 



    The OTNBridge makes use of the angularGuest module to set up the guest(s) inside the bridge. The syntax used with angularGuest to configure the components to bootstrap is: class="guest-component: componentToBootstrap guestId". The two divs have specified tagcloud as the component to bootstrap; fortunately, angularGuest has made arrangements to process tagcloud into a guest component, using the tagcloud Angular module. The guest is added to the bridge, registering it with a unique ID while providing a callback function to be used by the bridge to pass in messages from the host. In our case, this function will put any message received from the host in the local scope of the guest.


    jellema-html5-adf-fig09.png

    Figure 9


    When we run the tagcloud-bridge.html application using gulp serve or simply by loading the file into a browser, we will see two tagcloud instances, based on two distinct sets of tags. When we click on a tag in either cloud, that cloud will report the click to its own host. Both bridges are set up with a callback function that will simply show an alert with the contents of the message. When we integrate the OTNBridge and the tagcloud into the ADF application, we will do more useful things at the host level with these messages.


    jellema-html5-adf-fig10.png

    Figure 10



    jellema-html5-adf-fig10.png

    Figure 10


    Embedding the Angular Tagcloud Component in an ADF Taskflow

    The tagcloud component is running stand-alone. That is a good start. The next step is to embed this stand-alone application in an ADF application. You’ll find the end result in the adf-step2 folder. 


    jellema-html5-adf-fig11.png

    Figure 11


    The structure of this application is visualized in Figure 12:


    jellema-html5-adf-fig12.png

    Figure 12


    The Angular modules angularGuest and tagCloud have been containerized in a single file, tagcloud.js. The OTNBridge and OTNBootstrapper have likewise been merged into the integration.js file. These two files are all we need to add to the ADF application to make the tagcloud available.


    The ADF application has only a ViewController project. It contains a single page—MainPage.jspx—that has a region in which the task flow tagcloud has been bound. No parameters are injected into this task flow and no events are exchanged. The taskflow is completely self contained. Note that this page imports the two JavaScript files discussed in the previous section, to make them generally available inside our page.


    The taskflow consists of a single page fragment (tagcloud.jsff), in which there is a PanelGroupLayout component with its styleClass attribute set to “guest-component: tagcloud tc1;”. That may sound a little familiar; it is the same directive that we used in the stand-alone Angular tagcloud application to tell the bootstrap mechanism that a guest component of type tagcloud should be injected, identified in this case by the key tc1. And that is exactly what it means here as well.


    The managed beans (mBeans) in the tagcloud taskflow—otnBridge and tagCloudBean—take care of the rest of the logic. The initialize method in class OTNBridge is invoked through a trick: the EL expression on the icon attribute of the PanelBox causes the getInitialise() method to be invoked on the tagCloudBean mBean that subsequently invokes the otnBridge . This bean writes a JavaScript snippet to the page that invokes function bootstrapGuestModules() for the PanelBox. The PanelgroupLayout inside the PanelBox will be located during this bootstrap because of its guest-component directive and will have the tagcloud injected.


    During the bootstrap, a sendMessageToHost() function is registered for the guest. The way to send a message from the Angular guest component to the ADF host is through an ADF custom event. It is published on the client side by the Angular component that has no ADF knowledge, but simply invokes the hostCallBack function that the guest has stipulated. This registered sendMessageToHost() function will find the host ADF component and publish the custom event guestMsg on it, with the msg to be handed to the host as its payload.


    jellema-html5-adf-fig13.png

    Figure 13


    The server-listener in the page fragment is subscribed on the guestMsg event. When the event is consumed, it will call the tagCloudEvent method in the tagCloudBean mBean. This bean can do anything with it  (e.g., use the event to update the ADF logging component that displays the most recently clicked tag).


    At this moment, the tags are defined in method getInitialise() in the TagCloudBean, so inside the tagcloud taskflow. In order to have a reusable and encapsulated tagcloud component, this has to change. Our next step with the implementation will be to feed the tags into the taskflow through an input parameter. That will turn out to be but a very small step.


    Feeding Data Into The Angular Component Using Taskflow Input Parameters

    The previous section demonstrated how the tags to be displayed in the tagcloud are defined in the TagCloudBean. Instead of that hard-coded definition, to achieve reusability of the tagcloud component we have to make use of tag definitions that are injected into the tagcloud taskflow. Taskflows can expose input parameters that consumers of the taskflow use to pass values in. It is a small step to define a taskflow input parameter called tags of type java.util.List. We expect this parameter to have a value of type List<Tag>; it is mapped to #{pageFlowScope.tagCloudBean.tags}. Some small changes are made in the TagCloudBean: a property tags of type java.util.List<Tag> is added to support the input parameter’s destination. Additionally, method getInitialise() is modified to take the tags from the input parameter and use them to send a JSON message to the guest, which will use the message to update the tags in the tagcloud.


    jellema-html5-adf-fig14.png

    Figure 14


    The ADF application in the adf-step3 folder has implemented these steps. The tagcloud taskflow defines an input parameter called tags. The region binding is configured with an EL expression that links the viewScope animalCloud bean’s tags property to the tags input parameter. As a result, the tagcloud is populated using the tags produced by the animalCloud bean, which lives completely outside the tagcloud taskflow.


    This means that reuse of the tagcloud is now within reach. We simply create a second region binding with the taskflow and configure a different mBean to provide the tags—and our page now contains two separate tagclouds. The figure below shows how that is set up.


    jellema-html5-adf-fig15.png

    Figure 15


    Publish “Tag Click” Events From The Tagcloud To The Consuming ADF Container

    Apart from playing with the 3D animations (of course), the most important interaction users will have with the tagcloud will be selecting tags. Depending on the use case, a click on a tag may have a specific meaning that requires a specific reaction. Clearly, this action has to be taken outside the tagcloud, precisely because it depends on the use case. It is important, therefore, that the event of a clicked tag be reported outside the tagcloud taskflow, allowing the embedding page to respond.


    Publishing events from a reusable taskflow is an intrinsic part of ADF. The designated mechanism is called “contextual events.” The TagCloudBean will be the publisher of a contextual event whenever it receives the tag-has-been-clicked event from the Angular tagcloud component. We have already seen how this event travels on the client side to function sendMessageToHost(), which publishes a custom client side ADF event called guestMsg. The server listener in tagcloud.jsff is the final bridge to the tagCloudEvent(ClientEvent evt) method in the TagCloudBean. The payload of the evt Map object contains the msg object, also a Map, which has a single entry: the key is clicked and the value is the identifier for the tag that was clicked.


    Contextual events are published through a POJO Data Control. Look in the adf-step4 folder in the sources; in the ADF application, you will find the Java Class TagClickedEventPublisher, which contains a publishEvent() method. A Data Control has been generated for this POJO. The TagCloudBean will use this Data Control to tell the world about the tags that have been clicked.


    To be able to publish events from the context of the tagcloud.jsff page fragment, we have to create a method binding for the data control’s publishEvent method. In the page definition file, we specify that execution of this binding should publish the TagClickedEvent. We invoke this binding in method publishEvent() in the TagCloudBean, passing the selected tag as the event’s payload.


    This completes the responsibility of the tagcloud component: the event is published. It is now up to other parties to consume the event (or not) and make the most of it. Or not.


    jellema-html5-adf-fig16.png

    Figure 16


    Contextual events can also be consumed through an operation binding for a POJO data control. We may have multiple event consumers for the same event, each handling the event in a different way.


    The MainPage has been extended just a little with an inputText element that displays the content of the “animals” property in the “zookeeper” bean. Whenever a tag is clicked in the animal tagcloud, we want the selected animal to be added to this property. To that effect, we create a new Java Class, ZooTagClickedEventConsumer. This class contains a single method, which takes the event payload as its input. It retrieves the zookeeper mBean and adds the selected animal that it has extracted from the event payload. The zooKeeper bean finally refreshes the animal’s inputText element in the page.


    We generate a Data Control for class ZooTagClickedEventConsumer. Then we create a method binding for its handleEvent method in the page definition for the main page. We also create an eventMap in this page definition that hooks up the method binding to TagClickedEvent—but only when it has been published from the first region (which we set up to display the animal kingdom).


    jellema-html5-adf-fig17.png

    Figure 17


    With all these event-handling capabilities on board, we can run the application in the adf-step4 folder and see the inputText refreshed when we click on an animal tag.


    It turns out to be fairly trivial to also support event handling for the “cat” tagcloud. In fact, all we need to do is create a second event consumer class, generate a data control for it, and configure a method binding for its handleEvent method that is associated with the TagClickedEvent published from the second tagcloud region.


    jellema-html5-adf-fig18.png

    Figure 18

     

    Publish “New Tag” Events From The Consuming ADF Container

    The final piece of the puzzle is the publication of events in the containing ADF context that should influence the tagcloud component. Remember that we can send messages into the Angular Tagcloud guest. Such messages are put on the scope and thereby made available to the UI components in the tagcloud by way of Angular’s two-way data binding mechanism. The only data value that the tagcloud will understand is the tags object, which should be a map with tag definitions. In fact, during its initialization the TagCloudBean sends a message to the tagcloud guest from the updateTags() method with a JSON string defining this collection of tag objects.


    This is exposed in the application as shown in Figures 19 and 20.


    The user can type a new tag value in a text field and then press a button to have it added to the tagcloud:


    jellema-html5-adf-fig19.png

    Figure 19


    The new tag value is wrapped in an event, published, consumed, and used to update the tagcloud:


    jellema-html5-adf-fig20.png

    Figure 20


    We must now publish a contextual event of type NewTag whenever a new tag should be added to a tagcloud component. This event should contain the definition of the new tag as well as the client identifier for the specific tagcloud to which it should be added. The latter is necessary because we do not want new tags to be added to all tagcloud instances on the page.

    The class NewTagEventPublisher is used to publish the ADF Contextual Event, a simple POJO with a single method—publishEvent—for which a Data Control has been generated. An operation binding for this method is created in MainPage, and configured to publish the NewTagEvent. The zooKeeper bean handles a button click on the Add Animal button. The value in the new animal inputText component is passed by zooKeeper to the NewTagEventPublisher, along with the client identifier (the id of the region component for the animal kingdom tagcloud taskflow). The publisher creates a NewTagEvent out of this information. As before, this is where the responsibility of the event publisher ends. It is now up to the tagcloud to consume and process the event.


    The NewTagEventConsumer class is created to receive the NewTagEvent. A Data Control is created for this class. An operation binding for its handleEvent method is added to the page definition for the tagcloud page fragment and is configured to consume the NewTagEvent, from whatever publisher. Because the tagcloud component does not know in what contexts it will be used, it cannot in advance be selective about the event producers it wants to listen to.


    The handleEvent method will extract the tag and the client identifier and pass them to the handleNewTagEvent method on the TagCloudBean. The NewTagEvent is consumed by all instances of the tagcloud taskflow; therefore, this method checks whether the client identifier associated with the event corresponds with the identifier for which the instance of the TagCloudBean was set up. If the two match, the new tag is added to the tags collection and the updateTags method is invoked. This method creates the JSON message and then engages the OTNBridge to speed the message onwards, to the Angular scope and finally the tagcloud itself.


    Figure 21 shows what the flow is for the events that originate in the containing ADF context and are consumed into the tagcloud.


    jellema-html5-adf-fig21.png

    Figure 21


    Some Thoughts on Skinning, Internationalization and Customization

    Enterprise applications developed with ADF will typically make use of one or more skins to determine the look and feel of the application. The boilerplate text in the application (e.g., prompts, titles, hints and messages) is internationalized through language-specific resource bundles. And ADF offers an advanced mechanism—customization—that allows the application to show different faces depending on the user context, such as department, role or even age, and to remember run-time preferences set by the users.


    When an ADF application has an embedded Angular component, such as our tagcloud, it would be desirable to have the skinning, resource bundles and customization from ADF carry over to the component.


    The first requirement for this to be possible at all is that the Angular component expose entry points or hooks through which it allows the host to influence styling, boilerplate text and other characteristics. The second condition is that in the ADF application we can get hold of the information on styling, internationalization (also referred to as i18n) and customization, and develop a way to pass that information to the Angular component.


    We are not overly lucky with the tagcloud component in this respect: it does not expose either styling hooks or boilerplate text related input parameters. All it will do is display tags. For the purpose of this article, in which we want only to show that ADF skinning and i18n can be injected into any embedded Angular component, this will be enough. We already have a mechanism to transfer information from the ADF host to the Angular client. Through this mechanism, we are able to put objects in the Angular data scope—similar, conceptually speaking, to the pageFlowScope for ADF Taskflows. Angular components can easily access objects in this scope and therefore make use of styling or i18n-related data we put there from the ADF host.

    Our challenge now becomes to prove that we can extract styling data produced from the ADF skinning mechanism and get this information into the Angular scope. With the tagcloud, we can demonstrate that last part by displaying the style properties as tags in the tagcloud, as shown in Figure 22.


    jellema-html5-adf-fig22.png

    Figure 22


    We know that a component’s true colors as a result of styling are displayed in the browser only when the skinning mechanism has taken into account client details (such as device and browser) to produce the appropriate CSS definitions. If we want to know what the CSS properties of a specific component are, we have to inspect that component in the client at run time and learn about its computed style. Using JavaScript, it is fairly simple to make that assessment (see function getStyle in integration.js). The trick we apply now is to add one or more ADF components to tagcloud.jsff. These components—such as the af:showDetailHeader and af:commandButton in the next illustration—are not meant to be displayed to the end user. They have their visible attribute set to false. However, they will be included in the browser Document Object Model (DOM), with their style properties set (except for the display property which is set to “none,” obviously). This means that at run time, a number of known components have style properties derived from the ADF skinning engine. We can inspect these components from JavaScript and compose a JSON message from our findings. This message is sent to the guest, the tagcloud component, which, in our example, can use them only to display tags. Future components could actually use these properties to determine aspects of their look and feel.


    jellema-html5-adf-fig23.png

    Figure 23


    The application in adf-step6 contains this style-injection approach. It also has a skin selector and a custom skin. By selecting a different skin, the look and feel of the ADF components is changed, according to the skin definition. And because the hidden components, from which we derive the style properties, are also changed when a different skin is selected, a fresh set of data is passed into the tagcloud component with the latest styling details.


    Figure 24 shows the contents of the tagcloud for three different skin selections:


    jellema-html5-adf-fig24.png

    Figure 24


    A similar approach can be used for resource bundle entries. Again, we need to collect information in ADF and at run time—depending on the currently selected locale—and pass it to the Angular scope for the embedded component to do something useful with it. There are several ways in ADF to retrieve information from resource bundles. One fairly straightforward way is through the use of a component in the tagcloud.jsff page fragment that is not to be displayed, but that acts as the placeholder “dictionary” for the resource bundle entries.


    jellema-html5-adf-fig25.png

    Figure 25


    The desired resource bundle entries are created in a JSON style string in the clientAttribute of this placeholder component. The string is composed using EL expressions that reference the resource bundle (#{bnd.key}) that has been configured in the faces-config.xml file of this application. At run time, the string available in the client will contain the resource values based on the currently selected locale.


    A simple JavaScript function (extractTagsForResourceBundleEntries) locates the dictionary component, retrieves its clientAttribute and sends a message to the tagcloud guest with a tags object containing a single tag for each entry in the clientAttribute.


    Figure 26 illustrates this process.


    jellema-html5-adf-fig26.png

    Figure 26


    In the sample application in the adf-step6 folder, we have configured three resource bundles (for English, Dutch and German) with a small number of entries. The application also has a language switcher. When a different language is selected and the page is refreshed, the JavaScript function will execute again and send a new set of resource bundle entries into the tagcloud, based on the language that was newly selected.


    Our sample application will show three sets of tags, depending on the language, as is shown in Figure 27:


    jellema-html5-adf-fig27.png

    Figure 27


    We know that we can send internationalized values into the Angular component. It would be fairly easy to have an Angular component retrieve these strings from the Angular scope and use them for boilerplate texts in the component. These texts are then automatically internationalized, too, driven by the ADF resource bundle mechanism.


    Passing customized and personalized values into the embedded component can be done in a similar way. We know how to send data to our guest and we have several ways—including programmatic on the server side and using JavaScript and invisible placeholder components in the client—to get hold of customized values. That means we can make certain aspects of our embedded components customized as well, driven by Oracle Metadata Services (MDS) and the ADF Customization and Personalization infrastructure.


    Integrating the Tagcloud in the World Cup Football 2014 Match Center Application

    With all these new findings, tricks and components at our disposal, we will integrate the tagcloud to replace the boring list of tags that is currently displayed next to the match table in the World Cup Football 2014 Match Center application.


    jellema-html5-adf-fig28.png

    Figure 28


    The tagcloud is populated with the results from a ViewObject that uses a little fancy SQL to automatically derive various tags, such as surprise, intercontinental, derby, knock out stage, exciting, early, penalty shootouts, south.


    We will use the tag clicked event to add the tag to the list of those used to filter the matches in the ViewObject. In other words: clicking on a tag means removing from the table all matches to which the tag does not apply. Clicking on tags knock out stage and surprise will quickly give you a listing of all matches that were played in the knock out stage of the tournament and whose result was a surprise based on the FIFA ranking of national teams:


    jellema-html5-adf-fig29.png

    Figure 29


    As soon as the new selection of matches has been determined (based on the selected tags) the new list of tags is derived and published in a contextual event. The tagcloud is refreshed based on that event to show only the tags for the remaining matches.


    The tagcloud thus becomes a powerful instrument for quickly finding matches with specific characteristics. The quick exchange of tag-clicked and tags-retrieved-from-new-matches-selection events result in a smooth interaction between a pure data-bound ADF component (the rich table with matches) and a pure embedded Angular component (the tagcloud).


    The match number column sports a contextInfo marker. When it’s activated, the match details popup appears, providing additional information about the events during the match.


    jellema-html5-adf-fig30.png

    Figure 30


    The Tags tab gives an overview of the tags currently associated with the Spain vs. The Netherlands match. Most tags have been auto-derived and three have been applied manually: referential integrity, revenge and super goal.


    Users can add new tags that they feel should be applied to the match. They can enter their own tag value and make use of tag values that have been used for other matches. The figure below shows how a new tag repeat of 2010 is added, indicating that this match is a repeat of a match played at the 2010 World Cup tournament (where it was the final).


    jellema-html5-adf-fig31.png

    Figure 31


    When the green Add icon is clicked to confirm the new tag, the new tag event is published by the tagcloud component and consumed by the host ADF application. The new tag is handed to the ADF Business Components (BC) Model and inserted into the database. Subsequently, the tagcloud is refreshed, showing the newly applied tag.


    jellema-html5-adf-fig32.png

    Figure 32


    When the popup is closed and the match selection refreshed, the new tag is included in the tagcloud across all matches:


    jellema-html5-adf-fig33.png

    Figure 33


    Summary

    In this article, we have created a standalone tagcloud component using AngularJS, a 3D tagcloud component from the community, and standard HTML5. We have embedded this component in an ADF application and created various forms of interaction from the ADF context to the tagcloud component, using input parameters, two-way events, and even skin properties and resource bundles entries. Finally, we have realized our initial objective of adding a tagcloud to the Match Center application.


    This article has demonstrated that it is possible to bring to ADF the world of pure HTML5 development using the popular AngularJS framework. We can select components from a vast library of reusable artifacts available from the global community of HTML5 developers and embed them in our own ADF applications. These embedded components can participate in the infrastructure of the ADF framework. This includes use and manipulation of data from ADF Data Controls, styling driven by ADF skinning, and internationalization and customization based on ADF’s corresponding mechanisms.


    The example of the World Cup Football 2014 application will hopefully inspire and guide you into further enriching your own ADF applications.


    About the Authors

     

    Paco van der Linden is first and foremost an ADF specialist. Up until 2011, Paco was one of the leading ADF experts for Oracle in The Netherlands. In the second half of 2011, he left Oracle to continue his work as an ADF consultant for AMIS Services, an Oracle Partner.  More recently, Paco has investigated and worked with several other web development frameworks, such as AngularJS.


    Lucas Jellema has been active in IT (and with Oracle) since 1994. An Oracle ACE Director specializing in Oracle Fusion Middleware, Lucas is a consultant, trainer, and instructor in diverse areas including Oracle Database (SQL & PLSQL), Service Oriented Architecture, ADF, and Java. He is the author of the Oracle SOA Suite 11g Handbook, and a frequent presenter at JavaOne, Oracle Open World, ODTUG Kaleidoscope, Devoxx, OBUG and other conferences.
      Connect with Lucas Jellema ace-director.gif twitter-icon.gif blog-icon.gif small_linkedin_logo.png

     

    Note: This article has been reviewed by the relevant Oracle product team and found to be in compliance with standards and practices for the use of Oracle products.