ADF 12c – Allow user to personalize the form items at run time using MDS based Change Persistence

Share this on .. Tweet about this on TwitterShare on LinkedInShare on FacebookShare on Google+Email this to someoneShare on TumblrBuffer this page

The requirement is easily written down: the web page contains a form with multiple form items. Each user should be allowed to personalize the form at run time. This personalization entails the ability to hide and show form items. When user has decided to hide and show specific items – this decision should be persisted across sessions so that when the user logins at a later date, the form items she has hidden are still invisible and the displayed ones displayed.

This article describes how to implement this particular requirement in an ADF 12c Fusion Web Application. Note: the same steps and code will do the job for ADF 11g.

 

ADF has built in support for customization – both at design time and run time. Customization can be defined at various levels (or layers as the terminology is). One of these layers – typically the most fine grained – is the user level. Customizations at user level are frequently called personalizations.

In order for an ADF web application to support customization and personalization, we have to configure a number of things:

  • a user-level customization class has to be configured in the adf-config.xml
  • ADF Security has to be configured – so users can be identified (so their personalizations can be stored and retrieved)
  • customizations has to be enabled in the properties of the View project
  • the specific customization we are interested in (personalizing the visible or rendered attribute on inputText components) has to be enabled in the adf-config.xml file
  • a managed bean is configured that receives the updated form item definitions and sends them to the ADF Change Manager that writes them to MDS
  • a simple JSF page is developed with a form and a shuttle component to indicate which form items are to be hidden or displayed

The page looks as follows in this example:

image

 
This video demonstrates the objective of this article and an overview of the implementation:

The implementation is described below:

1. User-level Customization Class has to be Configured in the adf-config.xml

image

2. ADF Security has to be configured – so users can be identified (so their personalizations can be stored and retrieved)

Default settings will do:

image

image

image

image

image

Next I have created a role and assigned to newly created users to this role:

image

3. User Customizations have to be enabled in the properties of the View project (across sessions)

image

4. the specific customization we are interested in (personalizing the visible or rendered attribute on inputText components) has to be enabled in the adf-config.xml file

Open the adf-config.xml file and open the source tab to add the following snippet:

  <adf-faces-config xmlns="http://xmlns.oracle.com/adf/faces/config">
        <persistent-change-manager>
      <persistent-change-manager-class>oracle.adf.view.rich.change.MDSDocumentChangeManager</persistent-change-manager-class>
    </persistent-change-manager>
    <taglib-config>
      <taglib uri="http://xmlns.oracle.com/adf/faces/rich">
        <tag name="panelFormLayout">
          <persist-operations>ALL</persist-operations>
        </tag>
        <tag name="inputText">
          <attribute name="visible">
            <persist-changes>
              true
            </persist-changes>
          </attribute>
          <attribute name="rendered">
            <persist-changes>
              true
            </persist-changes>
          </attribute>
        </tag>
      </taglib>
    </taglib-config>
</adf-faces-config>

The file now looks like this:

image

 

5. The FormManipulator managed bean

A managed bean is configured that receives the updated form item definitions and sends them to the ADF Change Manager that writes them to MDS.

The real magic of this article is probably in this bean. The definition is not spectacular:

package nl.amis.adfformmanipulation.view;


import java.util.ArrayList;
import java.util.List;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.model.SelectItem;

import oracle.adf.view.rich.component.rich.RichForm;
import oracle.adf.view.rich.component.rich.input.RichInputText;
import oracle.adf.view.rich.component.rich.layout.RichPanelFormLayout;
import oracle.adf.view.rich.context.AdfFacesContext;

import org.apache.myfaces.trinidad.change.AttributeComponentChange;
import org.apache.myfaces.trinidad.change.AttributeDocumentChange;
import org.apache.myfaces.trinidad.change.ChangeManager;
import org.apache.myfaces.trinidad.change.ComponentChange;
import org.apache.myfaces.trinidad.change.DocumentChange;
import org.apache.myfaces.trinidad.change.ReorderChildrenComponentChange;
import org.apache.myfaces.trinidad.context.RequestContext;
import org.apache.myfaces.trinidad.util.ComponentReference;

public class FormManipulator {
  
    private ComponentReference formRef;
     
    public RichPanelFormLayout getForm()
    {
      if (formRef!=null)
      {
        return (RichPanelFormLayout) formRef.getComponent();
      }
      return null; 
    }
     
    public void setForm(RichPanelFormLayout form)
    {
      this.formRef= ComponentReference.newUIComponentReference(form);
    }

    public List<SelectItem> getComponents() {
        List<SelectItem> fields = new ArrayList<SelectItem>();
        for (UIComponent field : getForm().getChildren()) {
            SelectItem si =
                new SelectItem(field, (String)field.getAttributes().get("label"));
            fields.add(si);
        }
        return fields;
    }

    public List<UIComponent> getDisplayed() {
        List o = new ArrayList();
        for (UIComponent field : getForm().getChildren()) {
            if ((Boolean)field.getAttributes().get("visible")) {
              o.add(field);
            }
        }
        return o;
    }
    
    public void setDisplayed(List<UIComponent> visible) {
        for (UIComponent c : visible) {
            _addAttributeChange(c, "visible",Boolean.TRUE);        
        }
        // for every element in getComponents that is not in visible we have to set visible to false (or rendered to false)
        List<UIComponent> out = new ArrayList<UIComponent>();
        out.addAll(getForm().getChildren());
        out.removeAll(visible);
        for (UIComponent c : out) {
            _addAttributeChange(c, "visible",Boolean.FALSE);
        }
        // refresh the form to have all show&hide take effect
        AdfFacesContext.getCurrentInstance().addPartialTarget(getForm());
    }

    private void _addAttributeChange(UIComponent uic, String attribName,
                                            Object attribValue) {
        FacesContext fc = FacesContext.getCurrentInstance();
        ChangeManager cm =
            RequestContext.getCurrentInstance().getChangeManager();
        ComponentChange cc =
            new AttributeComponentChange(attribName, attribValue);
        // add the change to the change manager; this persists the change to MDS  
        cm.addComponentChange(fc, uic, cc);
        // now also apply the change to the actual UI component itself
        cc.changeComponent(uic);
    }
}

image

The parent RichPanelFormLayout component that contains the items that are to be hidden or displayed is bound to the form property (note: the approach to binding the UI Component is based on http://www.ateam-oracle.com/rules-and-best-practices-for-jsf-component-binding-in-adf/).  The getComponents() method returns the entries for the shuttle component in the form of SelectItem elements. These are used to populate the shuttle. See how the select items are created from the UI Component children of the getForm().

The values of the shuttle (the already selected item displayed in the right side container) are derived from and pushed to the displayed property on the bean. The initial set of selected item is taken as all children under the form that have their visible attribute set to true.

image

When the outcome of the shuttle manipulation is pushed to method setDisplayed() – all items received by this method are made visible. All children under getForm() that are not in the visible list are made invisible. To make an item visible or invisible, we use the local method _addAttributeChange. This method retrieves the current change manager and registers the attribute change for the inputText item with it. This will make the change manager write this change to MDS. Subsequently, the change is affected immediately to the inputText component – in the last line of the method (cc.changeComponent()).

Finally, method setDisplayed() ensures that the rich panel form layout is registered as partial target to make sure that any changes to the items in the form are refreshed to the client.

This bean is configured in faces-config.xml:

image

 

6. Form page with shuttle for item selection

A simple JSF page is developed with a form and a shuttle component to indicate which form items are to be hidden or displayed

image

 

    The most interesting aspects have been marked. The selectManyShuttle that reads all its elements from the components property on the formManipulator bean and discusses the currently selected set of items with the value property on the same bean. The button does nothing in particular except make sure the current settings in the shuttle are posted to the server – and therefore to the formManipulator bean. Note that the Gender item is initially invisible. That can be changed at run time by users who like to add that item to their display.

    <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1" xmlns:f="http://java.sun.com/jsf/core"
              xmlns:h="http://java.sun.com/jsf/html" xmlns:af="http://xmlns.oracle.com/adf/faces/rich">
        <jsp:directive.page contentType="text/html;charset=UTF-8"/>
        <f:view>
            <af:document id="d1">
                <af:form id="f1">
                    <af:panelStretchLayout topHeight="320px" id="psl1">
                        <f:facet name="top">
                            <af:panelHeader text="Simple Form Page with Persistent Form Field Manipulation capability"
                                            id="ph1">
                                <af:panelBox text="Set order of form fields" id="pb12" disclosed="true">
                                    <af:panelHeader text="manipulate form fields" id="ph2"></af:panelHeader>
                                    <af:selectManyShuttle label="Select Form Items to Display" id="sms1"
                                                          leadingHeader="Hidden Items" trailingHeader="Displayed Items"
                                                          value="#{formManipulator.displayed}">
                                        <f:selectItems value="#{formManipulator.components}" id="si3"/>
                                    </af:selectManyShuttle>
                                    <af:button text="Apply Changes" id="b1"/>
                                </af:panelBox>
                            </af:panelHeader>
                        </f:facet>
                        <f:facet name="center">
                            <af:panelFormLayout id="pfl1" binding="#{formManipulator.form}" partialTriggers="b1">
                                <af:inputText label="First Name" id="it1"/>
                                <af:inputText label="Last Name" id="it2"/>
                                <af:inputText label="Gender" id="it3" visible="false"/>
                                <af:inputText label="Home Town" id="it4"/>
                                <f:facet name="footer"/>
                            </af:panelFormLayout>
                        </f:facet>
                    </af:panelStretchLayout>
                </af:form>
            </af:document>
        </f:view>
    </jsp:root> 
    
    
    

    Note: at this point, we need to make sure that his web page is accessible to our users. The steps are:

    – create a page definition for the JSF page

    – configure the security settings for this web  page and grant access to role admin

    image

     

    Running the personalizable web application

    The application can be run on the integrated weblogic server to get a first taste.

    Because of the configured security, we need to enter credentials:

    image

    The initial display of the form:

    image

    Let’s hide the First Name element:

    image

    and press apply:

    image

    The change is now persisted to MDS as a persistent personalization for user joe. When the user logs out and returns at a later moment, the change will still be there. The MDS document that contains the change is a document specific to the current JSF page (theForm.jspx) and the current user (joe). On the file system in my development environment, the file can be found here:

    /.jdeveloper/system12.1.3.0.41.140521.1008/o.mds.ide.deploy.base/adrs/ADFFormManipulationDemo/AutoGeneratedMar/mds_adrs_writedir/mdssys/cust/user/joe

    It looks like this:

    image

    At this point, when I login as user jane, the change will not be applied. After all, it is joe’s customization. Jane can create her own customizations – that are stored in a similar document and directory as joe’s:

    /.jdeveloper/system12.1.3.0.41.140521.1008/o.mds.ide.deploy.base/adrs/ADFFormManipulationDemo/AutoGeneratedMar/mds_adrs_writedir/mdssys/cust/user/jane

    image

     

    Resources

    Download the JDeveloper project with the sources discussed in this article: ADF12cFormManipulationDemo.

    Articles with adjacent topics include:

    Share this on .. Tweet about this on TwitterShare on LinkedInShare on FacebookShare on Google+Email this to someoneShare on TumblrBuffer this page

    ADF Performance Monitor: Measuring Network Time to Browser and Browser Load Time

    Share this on .. Tweet about this on TwitterShare on LinkedInShare on FacebookShare on Google+Email this to someoneShare on TumblrBuffer this page

    Recently we added a great new feature to the ADF Performance Monitor: network and browser load time information. Now you know exactly every end-user experience of your ADF application, in real-time. You can quickly resolve any performance bottlenecks with this end-to-end visibility. You can even drill down into an individual user to analyze the experience – to understand the ADF app behavior. The dashboard is improved with several overview and detail graphs that shows the layer (database, webservice, application server, network/browser loadtime) where the time is spent of your application. This is very useful to troubleshoot problems.

    The ADF Performance Monitor is an advanced tool specifically build for ADF applications and is aware of the intricacies of the ADF framework. It traces key ADF actions across tiers and services to provide end-to-end visibility and automatically maps each tier to easily visualize the relationship between them. This Tracing provides deep visibility into the cause of application performance issues down to the tiniest detail. Click here for more information. Continue reading

    Share this on .. Tweet about this on TwitterShare on LinkedInShare on FacebookShare on Google+Email this to someoneShare on TumblrBuffer this page

    Instrumenting, Analysing, & Tuning the Performance of Oracle ADF Applications

    Share this on .. Tweet about this on TwitterShare on LinkedInShare on FacebookShare on Google+Email this to someoneShare on TumblrBuffer this page

    Last week I presented at the  UKOUG’14 conference on instrumenting, analyzing, & tuning the performance of Oracle ADF applications. Instrumentation refers to an ability to monitor or measure the level of a product’s performance, to diagnose errors and to write trace information. Instrumenting gives visibility and insight of what is happening inside the ADF application and in the ADF framework (what methods and queries are executed, when and how often). These runtime diagnostics can be very effective in identifying and solving performance issues and end-user behavior. This enables developers and operations teams to quickly diagnose and solve performance problems in a test and production environment. This blog posts the slides from this session. It  shows how you can instrument your own ADF application and build your own performance monitor.

    Gauges_real_world

    Gauges_real_world

    Continue reading

    Share this on .. Tweet about this on TwitterShare on LinkedInShare on FacebookShare on Google+Email this to someoneShare on TumblrBuffer this page

    Oracle OpenWorld 2014: Non-life altering observations (but still interesting and useful)

    Share this on .. Tweet about this on TwitterShare on LinkedInShare on FacebookShare on Google+Email this to someoneShare on TumblrBuffer this page

    This article does not necessarily discuss the big themes and major stories of Oracle OpenWorld 2014. It does mention a number of facts that I discovered, overheard, observed or otherwise found out about during last week’s conference. They are not necessarily from formal Oracle sources, they have have been part of conversations on the demo grounds or sessions for which no slide evidence exists. Do not base major decisions on these notes – but perhaps look out for more evidence and/or quiz your local Oracle representative.

    The acronyms of last week are probably API, REST, JSON and JS – in addition of course to IaaS, PaaS and SaaS. NoSQL (Larry said it himself, it is Not Only SQL!) made some appearances of course. An important technology – Server Side JavaScript and Node.JS (a JavaScript application server). When it comes to authentication, OAuth 2.0 was the talk of the town.

    Live SQL is a soon to be released feature on OTN where database developers will be able to live run SQL statements. SQL Code samples that before would have required a local database to run can now easily be tested. Blog articles can refer to LiveSQL to have their sample code tried out. Oracle Documentation is said to refer to LiveSQL for its SQL statements to have them live executable.

    image

    image

    Oracle Rest Data Services (formerly known as Oracle APEX Listener) provides several key capabilities for the Oracle Database. REST Data Services accepts RESTful Web Service call URIs and directs them to the appropriate SQL statement or PL/SQL block. REST Data Services marshals data returned from SQL statements into JSON or .csv format. Oracle REST Data Services is a Jave EE-based provides flexibility by supporting deployments using Oracle Web Logic Server (WLS), Oracle Glassfish Server and Apache Tomcat. (see: http://www.oracle.com/technetwork/developer-tools/rest-data-services/overview/index.html)

    image

    Oracle SODA: Simple Oracle Data API – an API from Java, C and C# and perhaps others to more easily work with JSON documents in the Oracle Database. Working through (JSON aware) SODA promises to be much more convenient than for example having to go through the JDBC API in order to retrieve [data from]or manipulate JSON documents. The SODA API is organized like REST services – with Collection Management, CRUD operations, Query by Example on JSON documents.  (thank you Marco Gralike for this information)sodaOracleDB

    APEX 5.0 will soon have a formal Beta program. The production release may take until deep into Spring 2015.

    Oracle Enterprise Manager now also for managing MySQL: http://www.oracle.com/us/corporate/press/2301492 …

    WebLogic 12.1.3 has been certified against JDK 8 – it is has been declared fit for use with Java VM 8.

    The Oracle Cloud Marketplace is going to be tremendously important for partners such as AMIS to publish and sell extensions, integrations and add-ons to Oracle SaaS products as well as PaaS Services. Unfortunately, the marketplace is still in its infancy, as became clear on the demo grounds. We can publish and show case our products – to generate leads. However, there is not yet a mechanism to sell or monetize (subscription based) through this marketplace. The one key feature I would really expect and desire a marketplace to have.

    image

    The one cloud service I do not believe Oracle wants us to buy:

    image

    Stream Explorer is one of quite a few tools show cased by Oracle targeted at the Line of Business User (the non-technical IT consumer). This tool provides a visual, declarative, browser based wrapper around Oracle Event Processor and Oracle BAM. With Stream Explorer (whispered to be available within a few months) it is every easy to create explorations and dashboard on live [streams of]data – reporting in real time on patterns, correlations, aggregations and deviations.

    image

    Another Line of Business User tool is the Visual Analyzer in the BI Cloud. This cloud service allows anyone to upload data from for example Excel sheets and quickly create dashboards and reports on top of those. Currently you can upload up to 15 GB of data and once the BI Cloud fully integrates with the Database Cloud Service you can go way beyond that number. After the initial upload – which will create tables ‘under water’ – you can continue with additional uploads that will append data to these tables. Thus you can step by step create a Data Warehouse in the cloud.
    Embedded image permalink

    The Oracle SOA Suite Cloud Service will provide the full (or almost full) functionality of the SOA Suite (including Service Bus) as part of the Oracle PaaS platform.

    image

    Before this service is launched, we will first see the ICS (Integration Cloud Service) – to be launched in the next six months or so. This service is targeted at not-very-technical-users, to allow them to create fairly straightforward integrations between SaaS products.

    imageimage

    After creating the mapping (visually, declaratively using the Oracle Recommends TM mechanism for suggesting mappings) between the messages, the integration can be activated and invoked from the upstream system. The service offers facilities for monitoring and tracing the interactions. This image shows a failed interaction, for which some form of recovery should be performed.

    image

    Cloud Adapters have been and will be released for integration between SOA Suite on premise and various SaaS applications. Additionally, a Cloud Adapters SDK has been released to create additional custom adapters, not just for Cloud integration with SaaS products but also for on premise integrations. The Cloud Adapters SDK could easily have been called the [general purpose]adapters SDK. Oracle uses the Adapters SDK itself for creating the new SaaS adapters (for SalesForce, Eloqua, RightNow and others).

    Oracle is working on two products in the area of API management and governance, in addition to the 12c version of the Oracle Enterprise Repository (which seems slated for Summer 2015). The next few months should see the release of API Catalog – a fairly light weight browser based tool that presents APIs (services) to potential consumers of these services. In the API Catalog UI, developers can find meta data about the services and their usage. API Catalog uses harvesting to discover services from various directions including – but not limited to – Service Bus and SOA Suite. API Catalog is targeted at the design time. At run time, the API Manager also presents information about APIs in a browser based UI. This API Manager sits on top of Service Bus and – as its name suggests – is more than just a reporter on the APIs that are available. The API Manager is also used for collecting and analyzing metrics on the usage of the API.

    SOA Suite will have end-to-end REST support: in 12.2.1, Service Bus pipelines can operate directly on JSON variables – using JavaScript for JSON manipulation directly, without requiring JSON to XML conversion. In BPEL, a similar option will be available with variables of JSON type and an activity that manipulates JSON (and can if necessary for invoke actions to XML based partner links) convert between JSON and XML. Note that the Mobile Cloud Service – based on Service Bus technology – uses JSON and JavaScript as primary format and data shaping language in its v1 release.

    ADF 12.2.1 (Summer 2015) will also have more REST support: the ability to publish an ADF BC Application Module as REST service.

    The @adf_emg XML Data Control 1.0.0 available through JDeveloper Help -> Check for Updates.

    Some recent ADF DVT features – released in ADF 12.1.3 and MAF 2.0 – were demonstrated

     

    imageand some new ones as well (probably for 12.2.1?): The very cool Thematic Map Mashups:

    image

    And the N-box (already available in MAF) (here shown poorly visible as a mashup wit thematic map).

    image

     

    The new company wide user experience based on the Alta theme is documented and available for our own usage at: bit.ly/oraclealta .

    image

    And a picture of the Oracle UX lab at HQ in Redwood Shores – with UX VP Jeremy Ashley proudly keeping watch:

    Embedded image permalink

    The Oracle Developer Cloud will be extended with Coding in the Cloud: in browser editors for various types of code. JavaScript applications are explicitly targeted- with support inside the Developer Cloud for tools such as Bower, Gulp, Yeoman, Grunt and npm – on par with similar tooling in the Java EE domain. The code editors will be library aware – with syntax highlighting and code completion.

    image

     

    The Oracle Application Builder Cloud Service – not in the near future – is to be an in browser, visual, declarative drag and drop development environment for rich client applications. It seems to be something like the webapp alternative to MAX (the Mobile Application Accelerator for MAF apps)

    image

    The demo grounds had a pod for Oracle Forms. Really. Here is the proof:

    image

     

    I liked the animations where the cloud services are presented as the elements in the periodic table:

    image

    and solutions are created like molecules:

    image

    Is a yellow elephant in the sky similar to the pink elephant in the room?

    imageimage

    And the finally, the statue of the triple-limbed Oracle salesman who can shake your hands and shake you out simultaneously, just off Moscone North (and of course a spare foot for to put in your door):

    image

    Share this on .. Tweet about this on TwitterShare on LinkedInShare on FacebookShare on Google+Email this to someoneShare on TumblrBuffer this page

    Web- and Mobile-Oriented Architectures with Oracle Fusion Middleware – Oracle OpenWorld 2014

    Share this on .. Tweet about this on TwitterShare on LinkedInShare on FacebookShare on Google+Email this to someoneShare on TumblrBuffer this page

    Mobile applications as well as a large class of modern HTML5 web applications are built on top of an architecture with special provisions, such as RESTful services; the personal cloud, to provide a cross-device experience; push; cache; localization; scalability; and secure interaction with the enterprise back end. Gartner refers to this as the web-oriented architecture. Oracle Fusion Middleware offers key products (Oracle SOA Suite, Oracle Identity Management, and Oracle API Gateway) to implement this architecture, possibly in combination with cloud services such as Oracle Mobile Cloud Service, Oracle Messaging Cloud Service, and Oracle Storage Cloud Service. This session discusses the architecture itself and what it entails.

    This is the abstract for my first session at Oracle OpenWorld 2014. The slides for this session can be downloaded from the Content Catalog as well as from SlideShare: http://www.slideshare.net/lucasjellema/weband-mobileorientedarchitectureswithoraclefusionmiddlewareforxml-oow2014.

    The sources for the demonstration I showed are available from GitHub: https://github.com/lucasjellema/SampleIssueTrackerAngularJSwithSOASuite12cRESTbackend.

    Share this on .. Tweet about this on TwitterShare on LinkedInShare on FacebookShare on Google+Email this to someoneShare on TumblrBuffer this page