Publishing resources exposed by ADF Data Control in RESTful services using RestLet and JDeveloper 11g

0

The previous two articles on RESTful services using RestLet and developing in JDeveloper 11g – First Steps with RestLet 1.1RC2 in JDeveloper 11g – restful services 101 and Extending the RestLet application with support for POST/PUT to create and update Resources – used a static data set as source for the Resources. For real world services that will not be your typical scenario. Usually a business service hiding a persistence layer sitting on top of a database or wrapping a web service (RESTful or otherwise) is the more logical publisher of resources.

In this article, we will see how we can leverage ADF Model – Data Control & Data Bindings – to hook up such a business service. ADF Model publishes a Data Control for each Business Service it exposes. Through the Data Control applications can get access to data collections and operations acting on that data. For the application consuming the Data Control there should be no difference whether the underlying business service is an ADF BC application module connecting to a relational database, an EJB doing something similar, a web service published in the SOA of the organization or a RESTful service out there on the internet. That is at least the theory.

In this article, I will create a very simple Data Control, really nothing more than a mock object: a Placeholder Data Control. I will create a Thing data type and expose through the Placeholder Data Control a collection of Thing objects. The benefit of this approach is that we can take look at how ADF model can be used for providing the foundation for our RESTful services without the need for implementing a real business service. In a subsequent article we should find that the code we now write for the placeholder data control will work for ‘real’  data controls as well. ....

To be able to work with a Data Control in the application, we go through a so called BindingContainer, an object that ADF manages for us. The BindingContainer links our application to the bits and pieces – collections, operations – from the Data Control that we use in the application. These links are called Data Bindings. Depending on how we want to use the collections, we can use various types of data bindings, including table, list and tree bindings. The BindingContainer is typically instantiated based on a so called PageDefinition file, an XML file that contains the configuration of the data bindings, usually for a specific page – JSP, JSF, Swing, Excel (ADF di). In our RESTful case, we do not really have a page. We have a bunch of services (/things, /things/{thingName}). It seems easiest to create a page definition file that contains the data bindings for this bunch of services.

Finally, an easy way of calling ADF Model into action in our RESTful web application is by configuring the ADF Binding Filter in the web.xml, setup with the right URL pattern, to ensure that as a first step in handling requests to our RESTful services the ADF Binding Filter kicks in to set up the ADF BindingContext from which we can subsequently access the BindingContainer we need.

The steps are:

Create placeholder data control

From the New Gallery, Category Business Tier option Data Controls choose the item Placeholder Data Control. Provide a name – any name will do. I typed in ResourceDataPlaceHolder

Create data type and provide sample data

From the context menu on the new data control in the Data Control palette, choose Create Placeholder Data Type. In the window that opens, specify the Datatype – Thing – and its attributes – Name, SomeOtherProperty, AndThisToo, ImportantValue, ThisValueAsWell. On the Sample Data tab, provide some static sample data to use in this simple application.

The Data Control Palette now looks like:

Drag Thing to JSP, drop as table

Open the untitled1.jsp page. Drag the Thing collection from the Data Control palette and drop it on the JSP as a table. This will create a table element in the JSP page – which is of no interest whatsoever to us as we will never use the JSP as it is typically used: as the source of a web page. What is far more interesting and fairly useful as well is that JDeveloper has created the untitled1PageDef page definition – the design time specification for our BindingContainer. It is created with an iterator against our ResourceDataPlaceHolder Data Control and also contains a Table binding that we can use to access the data from the Data Control.

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&gt;<br />&lt;pageDefinition xmlns=&quot;http://xmlns.oracle.com/adfm/uimodel&quot;<br />                version=&quot;11.1.1.51.56&quot; id=&quot;untitled1PageDef&quot;<br />                Package=&quot;myfirstrestfulservice.pageDefs&quot;&gt;<br />  &lt;parameters/&gt;<br />  &lt;executables&gt;<br />    &lt;iterator Binds=&quot;Thing&quot; RangeSize=&quot;25&quot; DataControl=&quot;ResourceDataPlaceholder&quot;<br />              id=&quot;ThingIterator&quot;/&gt;<br />  &lt;/executables&gt;<br />  &lt;bindings&gt;<br />    &lt;table IterBinding=&quot;ThingIterator&quot; id=&quot;Thing&quot;&gt;<br />      &lt;AttrNames&gt;<br />        &lt;Item Value=&quot;Name&quot;/&gt;<br />        &lt;Item Value=&quot;SomeOtherProperty&quot;/&gt;<br />        &lt;Item Value=&quot;AndThisToo&quot;/&gt;<br />        &lt;Item Value=&quot;ImportantValue&quot;/&gt;<br />        &lt;Item Value=&quot;ThisValueAsWell&quot;/&gt;<br />      &lt;/AttrNames&gt;<br />    &lt;/table&gt;<br />  &lt;/bindings&gt;<br />&lt;/pageDefinition&gt;<br />&nbsp;

Note: the PageDefinition file is configured in the file DataBindings.cpx:

  &lt;pageMap&gt;<br />    &lt;page path=&quot;/untitled1.jsp&quot;<br />          usageId=&quot;myfirstrestfulservice_untitled1PageDef&quot;/&gt;<br />  &lt;/pageMap&gt;<br />  &lt;pageDefinitionUsages&gt;<br />    &lt;page id=&quot;myfirstrestfulservice_untitled1PageDef&quot;<br />          path=&quot;myfirstrestfulservice.pageDefs.untitled1PageDef&quot;/&gt;<br />  &lt;/pageDefinitionUsages&gt;<br />&nbsp;

When we want to get hold of this Page Definition at run time – or rather the BindingContainer derived from it – we need to address it through the page’s id: myfirstrestfulservice_untitled1PageDef.

Configuring the ADF Binding Filter

Our drag and drop operation caused one other useful thing to happen: JDeveloper has configured the ADF Binding filter in the web.xml file. This filter takes care of initializing the ADF Binding Context before the web application starts interacting with BindingContainers. However, the filter configuration created by JDeveloper is not exactly what we need: The URL pattern is set to only *.jsp and *.jspx whereas we need it to intercept every request to our RESTful services.

Therefore, we need to change the url pattern to *:

&lt;filter-mapping&gt;<br />  &lt;filter-name&gt;ADFBindingFilter&lt;/filter-name&gt;<br />  &lt;u
rl-pattern&gt;*&lt;/url-pattern&gt;<br /
/>  &lt;dispatcher&gt;FORWARD&lt;/dispatcher&gt;<br />  &lt;dispatcher&gt;REQUEST&lt;/dispatcher&gt;<br /> &lt;/filter-mapping&gt; <br />

Make the Thing table binding available to the application

Assuming that we may want or need access to the Thing table binding from more than one location in the application, we can expose it through a central method, for example in the RestfulApplication class. This method gets hold of the ADFContext, the BindingContext and finally retrieves the BindingContainer and from it the table binding:

    public static JUCtrlRangeBinding getThingsTableBinding() {<br />        ADFContext ctx = ADFContext.getCurrent();<br />        OracleExpressionEvaluatorImpl elev =<br />            (OracleExpressionEvaluatorImpl)ctx.getExpressionEvaluator();<br />        HttpBindingContext data = (HttpBindingContext)elev.evaluate(&quot;${data}&quot;);<br />        DCBindingContainer bc =<br />            data.findBindingContainer(&quot;myfirstrestfulservice_untitled1PageDef&quot;);<br />        bc.refresh(DCBindingContainer.PREPARE_MODEL);<br />        JUCtrlRangeBinding tableBinding =<br />            (JUCtrlRangeBinding)bc.findNamedObject(&quot;Thing&quot;);<br />        return tableBinding;<br />    }<br />&nbsp;

Before actually grabbing the tableBinding, the class first initializes the BindingContainer (refresh(DCBindingContainer.PREPARE_MODEL).

Publishing things from the ADF Data Control

The final step in our mini quest is the implementation of the ThingsResource’s represent() method – that handles the GET request – using the things table binding. We do a little preparation before getting to the present method:

add the private member thingsTableBinding

JUCtrlRangeBinding thingsTableBinding; <br />

and add code in the constructor to set that property:

  ...<br />  thingsTableBinding= RestfulApplication.getThingsTableBinding();<br />  ... <br />

Now we can do business in represent() – instead of iterating the things Collection, we now deal with rows from the TableBinding:

    /**<br />     * Returns a listing of all registered things.<br />     */<br />    @Override<br />    public Representation represent(Variant variant) throws ResourceException {<br />        // Generate the right representation according to its media type.<br />        if (MediaType.TEXT_XML.equals(variant.getMediaType())) {<br />            try {<br />                DomRepresentation representation =<br />                    new DomRepresentation(MediaType.TEXT_XML);<br />                // Generate a DOM document representing the list of<br />                // items.<br />                Document d = representation.getDocument();<br />                Element r = d.createElement(&quot;things&quot;);<br />                d.appendChild(r);<br />                <br />                    RowIterator ri = thingsTableBinding.getRowIterator();<br />                    ri.reset();<br />                    Row[] rows  = ri.getAllRowsInRange();<br />                    <br />                    for (Row row:rows) {<br />                        // every row means a new thing<br />                        Element eltThing = d.createElement(&quot;thing&quot;);<br /><br />                        Element eltName = d.createElement(&quot;name&quot;);<br />                        eltName.appendChild(d.createTextNode((String)row.getAttribute(&quot;Name&quot;)));<br />                        eltThing.appendChild(eltName);<br />                        Element eltDescription = d.createElement(&quot;description&quot;);<br />                        eltDescription.appendChild(d.createTextNode((String)row.getAttribute(&quot;SomeOtherProperty&quot;)));<br />                        eltThing.appendChild(eltDescription);<br /><br />                        Element eltAndThisToo = d.createElement(&quot;andThisToo&quot;);<br />                        eltAndThisToo.appendChild(d.createTextNode((String)row.getAttribute(&quot;AndThisToo&quot;)));<br />                        eltThing.appendChild(eltAndThisToo);<br /><br />                        Element eltImportantValue =<br />                            d.createElement(&quot;importantValue&quot;);<br />                       <br />                        eltImportantValue.appendChild(<br />                             d.createTextNode((((oracle.jbo.domain.Number)row.getAttribute(&quot;ImportantValue&quot;)).toString()))<br />                           );<br />                        eltThing.appendChild(eltImportantValue);<br />                        r.appendChild(eltThing);<br />                    }<br />                d.normalizeDocument();<br />                // Returns the XML representation of this document.<br />                return representation;<br />            } catch (IOException e) {<br />                e.printStackTrace();<br />            }<br />        }<br />        return null;<br />    }<br />&nbsp;

The most interesting part is at the beginning – though still not very interesting – where we get the RowIterator from the TableBinding and after resetting it get all rows from it. Next we loop over the rows and create an XML element for each thhing row.

We access the things service in the same manner as before – by reloading the /things url in our browser.

Adding the Start Row and Max Rows functionality

One interesting feature in Data Services is the ability to scroll through pages of data. Instead of always starting a list at the first resource and always showing every last one of the resources in the list, we would like to indicate that we prefer to see the rows in ‘pages’ – ranges of rows – and that we would like to start at some specified but arbitrary row in the set – not just the first one.

Our URL will look something like:

http://host:port/webapp/things?start=26&maxRows=25

for example to request the second page of 25 records from the things list.

It turns out to be a very simple task to add this functionality to our RESTful service. In the ThingsResource we add two private members:

    int startRow=0;<br />    int maxRows=-1;<br />&nbsp;

In the constructor for that class we retrieve the values of these parameters from the Request – note: they may not be provided in the url!

        String startRowParam = request.getResourceRef().getQueryAsForm().getFirstValue(&quot;start&quot;);<br />        if (startRowParam!=null) {<br />            startRow = Integer.parseInt(startRowParam);<br />        }<br />        else {<br />            startRow = 0;<br />        }<br />        String maxRowsParam = request.getResourceRef().getQueryAsForm().getFirstValue(&quot;maxRows&quot;);<br />        if (maxRowsParam!=null) {<br />            maxRows = Integer.parseInt(maxRowsParam);<br />        }<br />        else {<br />            maxRows = -1;<br />        }<br />&nbsp;

In the represent() method we make a minor change – we add two rows:

  ri.reset();<br />  ri.setRangeSize(maxRows);<br />  ri.setRangeStart(startRow);<br />  Row[] rows  = ri.getAllRowsInRange(); <br />

The second and third line were added.

Here we can leverage the standard functionality in the RowIterator for scrolling through ranges of rows.

We can again access our services from the browser and see the effect of these two new parameters:

 Start at row 3 (start = 2)

Note: when the range size is larger than the number of rows the Row Iterator would produce using a given start row, it tends to add rows in the getAllRowsInRange() result, try
ing to ge
t all of the RangeSize rows. Since our sample data set only has 3 records, you really need to provide the maxRows parameter at a value of 1 or 2 in order to see the effect properly demonstrated. Note: the start parameter is 0-based: when you want to see the first row, the parameter should be set to 0. When you want to start at the second resource, it should be set to 1. You may want to do that somewhat differently to not alienate your service consumers.

Summary

In three articles we have seen how to get started with the RestLet library for creating RESTful services. We have used the brand new JDeveloper 11g IDE although of course apart from this final section on leveraging ADF the articles pretty much apply to any IDE. I can conclude that creating RESTful services that expose resources on intuitive easy to access URLs is pretty straightforward. Providing support for C(R)UD operations is also simple. Hooking it up with ADF and indirectly – not yet implemented but within reach – with enterprise business services is now a piece of cake.

With the recent release of the JSR-311 and its Reference Implementation (Jersey), it is an obvious next step to implement this and the previous articles using that JSR-311 API that RestLet supposedly also implements – or will implement shortly.

Resources

Download the JDeveloper 11g Application RestLetWithADFDataControlIntroduction.zip .

Share.

About Author

Lucas Jellema, active in IT (and with Oracle) since 1994. Oracle ACE Director for Fusion Middleware. Consultant, trainer and instructor on diverse areas including Oracle Database (SQL & PLSQL), Service Oriented Architecture, BPM, ADF, Java in various shapes and forms and many other things. Author of the Oracle Press book: Oracle SOA Suite 11g Handbook. Frequent presenter on conferences such as JavaOne, Oracle OpenWorld, ODTUG Kaleidoscope, Devoxx and OBUG. Presenter for Oracle University Celebrity specials.

Comments are closed.