JDev 12.2.1.3: Creating a shared skin jar (Part 2)

In part 1 or the series we created a simple skin, built an ADF-Library from it and tried to reuse it by deploying it to a WebLogic Server. This approach failed. In this part, we try another option to share a jar with

Sharing the skin with other applications

To share the skin with other application we can

  1. Create an ADF Library
    1. Add this library to the other application
    2. Add this library as a shared library to a WebLogic Server
  2. Create a normal jar
    1. Add this library to the other application
    2. Add this library as a shared library to a WebLogic Server

For this blog the way we want to use if 2b. This allows to create the skin once, deploy it to a server and use it in every other application. In the next paragraph, we try out option 1a to show the problems when reading resources from a jar file.

Using a shared skin

Option 2b

Here we create a jar file containing the skin and additional resources like images and deploy it directly to a WebLogic Server as a shared library. The advantage is, that other applications can use the skin and other resources directly and that the jar can be versioned to allow different versions of the same jar on the server.

Option 1a which we discussed in the previous chapter doesn’t work for images. However, the documentation ‘Deploying a Custom Skin File in a JAR File’ and Frank Nimphius pointed it out in e.g. 86. Reading boilerplate images and icons from a JAR or How-to share skin definition files across applications how the jar file must be structured to allow the resource servlet to read the resources. The essential sentence is

‘All image resources and CSS files must also be under the META-INF directory.’

In his article, Frank suggested using the command line jar tool to create the jar. I show how to use JDev to create the jar with the needed structure and how to deploy it to a server as a shared library.

A sample application is used to use the skin and to show an image load from the jar.

The building plan for a skin in a shared Library which can be deployed to a WebLogic server is given in the article as:

To implement the shared library approach, developers need to change their existing skin definition so it can be deployed in a JAR file. The steps for this include

– Creating a META-INF directory – Creating a trinidad-skins.xml file that defines the skins deployed with the JAR file

– Creating an META-INF/adf sub directory for images and icons served from the JAR file

– Changing the image reference in the CSS to include the “adf” directory, which makes sure images and icons are handled by the ADF Faces resource loader, which can read resources from JAR files

– JAR the META-INF directory to create the library file

Looking at the current project for the skin we see a different layout

In the article Frank instructed to create the needed folders yourself and copying or moving the files to the new structure, then to use the command line to build a jar from the structure.

I’ll show how this can be done with a special deployment descriptor from within the project. The image below shows the needed layout of the final jar file.

To transform the folder structure present in JDev to the needed structure of the final jar, we create a new deployment descriptor in JDev

In image 4 we see the first part of the solution: here we set the path inside the jar to ‘MEAT-INF’. This will guarantee the structure we need. Then we add another contributor to the list (public_html) to get everything we need into this folder. Then we use the ‘Filters’ node to select all content we need skin part

Next part is to create another path in the jar for the metadata of the skin

We add another file group for the resources

Now we can deploy the jar using the new deployment descriptor

And the jar file is created in the deploy folder. It holds all files in the right folders

Finally, we can deploy this jar to the WebLogicServer. In this case, I use the integrated WLS, but it can be any stand-alone WLS too.

The error message you see on the 7th image can be ignored. It only tells you that the library can’t be deployed as an application but only as a shared library. This is exactly what we want to do 🙂

Now the jar file is deployed on the WLS as a shared library and can be used for every application on this server.

We use the existing application from part one to consume the jar skin from the shared library and show the images deployed with the jar.

Before we go any further, we have to remove the ADF Library we added to show the problem from the project. For this open the project properties and select the ‘Library/Classpath’ node and remove the ‘ADFLibrary’ entry

The page should now look like no skin is used at all.

As we already added a skin (with the ADF Library) we don’t have to do this again. However, we have to add a library reference to configure the application to use the shared library deployed on the server. For this, we open the application descriptors and edit the ‘weblogic-application.xml’ file by double clicking the entry in the application resources section

In the ‘Shared Library Reference’ section, we add a reference to the now deployed shared jar ‘blogsharedskin’

Saving everything we don’t see any change to the page design, as the library isn’t part of the application yet. Starting the application we get

Just what we liked to see. The images are visible, checking the page with Chrome’s Dev Tools shows that the images are correctly loaded

This proves that the shared library with the skin and the images are working correctly.

To make the skin visible in JDev during development, we can add the jar we developed to the server a library. We create a library

and make sure the ‘Deploy by default’ is NOT set. Adding the library to the project

will make the skin visible in design mode

The unset checkmark prevents the jar from being packed into the WAR or EAR file. It’s just used in the IDE. That you can’t see the images is normal as there is no full server to serve the images to the design view.

Summary

In this mini-series, I showed the problem when creating a skin as ADF Library and trying to share it on a Weblogic Server. Then I showed how to create a deployment descriptor for the skin and other resources and how to deploy the resulting jar to a WebLogic Server.

The sample application can be downloaded from BlogSharedSkin. The sample was created by using JDev 12.2.1.3 but the same technique can be used in any 12.2.1.x JDev version. There is no database connection needed.

Advertisements

JDev 12.2.1.3: Creating a shared skin jar (Part 1)

In earlier versions of JDev, skins have been created either by pure code or by using the free Skin Editor. However, since JDev 12.2.1.x the skin editor has been integrated into JDeveloper itself.

A couple of questions in the ODC JDeveloper space are about how to create a skin with JDev which can be deployed as a shared library to a WebLogic Server. I gave this a try and it turned out, that you can build an ADF library jar from a skin project but you can’t use images to this jar which you might want to use in the application.

In this blog, I’ll show how to create a skin with resources like images and how to build a jar file from the skin together with the images and deploy it aa s shared jar to a WeblogicServer.

Building a skin project

The first part is to build a small skin project. The project we use to create a minimal skin, just to show that the skin is changing something. Then we add some images to the skin which we want to use in the application which uses the skin. Such images can e.g. used on an af:button component.

We start by creating a new application as an ‘ADF Fusion Web Application’

As we don’t need the created model project we delete it completely

If you get another dialog, telling you that you can’t undo the action, answer ‘Yes’ to delete the project. Now you should see a workspace with just the one project:

Know that we have a project we add a skin and e.g. add some skin selectors to change to the color of the button text. For this, we right click the ‘Web Content’ folder in the project and select ‘New from Garaly’ and then select ‘ADF Skin’ from the ‘JSF/Facelets’ node and fill in the basic information:

This will create the needed css file and the descriptors which define our skin (trinidad-config.xml and trinidad-skins.xml).

We open the sharedskin.css file if it’s not open already and switch to source mode. Here we add two simple skin selectors

which are changing the color of the text of a button and a link. You can add more sophisticated selectors but for this blog, it’s enough to show the working skin. To make it more interesting, and because that’s the real reason for this blog, we add some images to the skin which we like to use in the application using the skin. We add the images into a new folder like shown below

The reason for this structure is, that to read the images from the jar in the consuming application, we need a special resource loader. In case of ADF it’s the resource servlet which listens to the URL pattern ‘/adf/’’. This servlet is installed automatically for ADF Web Applications and is configured in the web.xml file

The final task for the skin project is to create a jar file which we can use in other applications. The easiest way to get such a jar is to create an ADF Library deployment descriptor. Open the project properties of the skin project and select the ‘Deployment’ node

And click the ‘New Profile’ icon, select to create an ADF Library Jar

and click ‘OK’. The remaining dialogs you can just click ‘OK’ or ‘Finish’.

To create the library we have to execute the descriptor by right-clicking on the project and selecting ‘Deploy’ and choosing the ‘sharedskinadflib’

This will create the jar in the ‘deploy’ folder of the project.

Sharing the skin with other applications

To share the skin with other application we can

  1. Create an ADF Library
    1. Add this library to the other application
    2. Add this library as a shared library to a WebLogic Server
  2. Create a normal jar
    1. Add this library to the other application
    2. Add this library as a shared library to a WebLogic Server

For this blog, we want to use option 2b. This allows to create the skin once, deploy it to a server and use it in every other application. In the next paragraph, we try out option 1a to show the problems when reading resources from a jar file.

Using a shared skin

Option 1a

We start with option 1a, just to show the problem when we try to read a resource from a jar. We build another ADF Fusion Web application and add the skin as ADF library from a ‘File System Connection’ which we create and let it point to the ‘deploy’ folder

Right-click on the ‘sharedskinadflib’ and add it to the new sample project. This will make the skin available to the application. To use the skin we have to add a skin to the application like we did to create the skin project. The difference is that we now choose the shared skin as the base skin

Creating a new page and adding a button and/or a link to the page we see the new style introduced by the ‘sharedskin’

So, the shared skin is working. Well, yes, but what about the images we added to the ‘sharedskin’?

Let’s try to add one to the button. In the property editor, we select the icon property of the button and click ‘Edit’ to get

However, we don’t see any image in the whole project. As we know where we put the images (or we can look into the sharedskinadflib) we can just add the path to the image like ‘skins/sharedskin/adf/images/home.png’ and we see the image

Running the application we get the page with the button but don’t see the image

Using DeveloperTools we see that the resource couldn’t be found. Inspecting the button element we see

The path to the image is not found 😦

If we change the address of the image to ‘/adf/images/home.png’ to use the resource servlet we still get an error

The reason is that the resource servlet expects the resources in a different path inside the jar. Every resource which should be read from a jar should be in a folder named ‘META-INF’.

The ADF library did not put the images into the META-INF folder

The problem is that we can’t change the layout of the ADF Library. When you create an ADF Library there is no option to make any changes to the content of the jar.

The conclusion is that using a skin in an ADF Library is problematic if there are other resources which you need to share.

To be continued…

In the final part 2 of the series, we see how the skin can be shared with other applications.

JDev 12c: Badge Button reloaded

In my article JDev: Badge Button I showed how to build a special button with a notification ‘badge’:

The declarative component of this sample was build using JDev 11g (11.1.1.9.0 to be exact).

I received a couple of question on how to work with this declarative component in JDev 12c projects. In general, you can use the same source and build the declarative component in JDev 12c. However, as JDev 12c is using a different document type, Facelets instead of JSP XML, you can use the badge button only on JSPX type pages.

So, in this blog, I show how to create a declarative component which is usable in Facelets type pages. I don’t change the behavior of the badge button but reuse the code. This blog is more about how to create a declarative component in 12c and show the differences to 11g.

JSPX vs. Facelets

With the introduction of JSF 2.0 (JavaServer Faces 2.0 Overview and Adoption Roadmap in Oracle ADF Faces and Oracle JDeveloper 11g) a new document type Facelets was introduced. The difference and the motivation behind this is outlined in the document.

We are only interested in the fact that you can’t mix components designed for JSPX XML pages or fragments with Facelets type pages or fragments. This means that you can’t add the badge button created for 11g to a jsf page of jsff fragment of type ‘Facelet’.

Building a Declarative Component for 12c

We start from the old application workspace I created for the 11g implementation. Opening this workspace will migrate it to the 12c. At the end of the blog, you’ll find a link to download the final workspace for 12c.

After the migration we add a new project ‘BBB12cDeclarativeComponent’ of type ‘ADF ViewController Project’ to the workspace:

After creating a new project for the 12c badge button, we create a new ‘Declarative Component’ in the ‘Web Content’ folder

In the wizard, we now select ‘Facelets’ as the document type. Selecting ‘Facelets’ will create the 12c kind of declarative component.

Once we finished the wizard, we get the skeleton declarative component in the ‘BadgeButton12c.jsf’ file. If you got a file name ‘BadgeButton.jspx’ you did not set the document type to ‘Facelets’.

Now we can copy the code from the original sample written for 11g and copy it after the componentDef tag. Once you copied the code from the original sample you have to change the EL used to address the action and the actionListener to match the componentVar property in the componentDef tag. To make this distinguishable from the 11g sample, I changed the componentVar to ‘compButton’. The other change is to use an af:button tag instead of the af:commandButton tag. While the af:commandButton tag can still be used, 12c application should use the af:button tag.

 

The final code looks like

Adding the declarative component to the faces palette

You already know, that to use the declarative component in a project, you first have to add it to the component palette. The difference to the 11g sample is that we have to choose a different node in the project definition to add the library.

First, we need to deploy the declarative component project to an ADF Library. For this, all we need to do is to execute the deployment profile created with the project

Next, we add a ‘File System’ resource which points to the folder the jar is created in

And the jar should show up

To make it usable in the view controller project, we have to add the jar to the project

Now, when we look into the view controller projects properties, we find the new declarative component in the ‘Facelets Tags Libraries’ node. In JDev 11g the tab libraries can be found in the node ‘JSP Tag Libraries’. Again, the difference is where the tags or declarative component are usable. You use JSP tags in JSP XML files and you use Facelets tags in JSF files.

Next step is to create a new JSF Page in the adfc-config.xml, the unbounded task flow.

Again, we make sure to select ‘Facelets’ as document type as we otherwise will not be able to use the declarative component created for ‘Facelets’.

The layout of the page is similar to the one for 11g. 12c uses a panelGridLayout instead of the panelStretchLayout, but that’s all.

As we are now using a JSF page and added the 12c component library and find the BadgeButton in the component palette

and use this on the page. The final layout looks like

Or when running the JSF page

Clicking the button we get the log messages

Sample Application

You can download the sample application from GitHub BlogBadgeButton12.2.1.2

JDeveloper: Info about the clicked cell in an af:table

JDeveloper allows to easily create tables with the af:table component. The table allows easy access to the selected row or rows. However, if you are interested in which cell of a table has been clicked, ADF needs some tweaking. This blog is about how to tweak an af:table to get exactly this info.

Use Case

You like to know which cell in an af:table a user has clicked, e.g. to get some detailed information about the clicked item or cell in the selected row. The sample I show get the information about the current row, and column of the cell and the value of the cell clicked. The final sample will show the info like

How to do it?

The normal af:table component doesn’t give information about the cell a user has clicked on. The ADF pivot table offers this but is complex to use.

We use JavaScript in form of a clientListener to intercept the click on a cell and a serverListener to call a bean method to get more data on the cell. This article 011. ADF Faces RC – How-to use the Client and Server Listener Component shows how to use clientListener and serverListener in detail.

As we are interested in the selected cell, we add a clientListerer to each af:outputText which shows the column value in the af:table which fires on the click event. The clientListener calls a JavaScript method. In the JavaScript method, we build a payload of the UIComponent which is used to show the column value and the column name of the cell. To get this information we have several possible ways:

  1. We can use our knowledge of the DOM tree and get the column via the parent of the component which fired the event. The parent component should be the af:column.
  2. We add a client attribute to the component which shows the cell value adding the column name from the af:column as EL

In this sample, we choose the second solution. With this information, we call the serverListener from the JavaScript method. The serverListener method is implemented in a request scope bean and uses the information passed to get the details about the clicked cell we show in the UI.

Implementation

The sample uses the HR DB schema and only needs one table, Employees in this case. We create a simple page with the table in read-only mode, sortable and filterable. As you see in the image above the table is just build be dragging the Employees VO onto the page and drop it as a read-only table.

Now we add a clientListener and a serverListener to each outputText component which is used to show the cell value

In the image above we see the listener for two columns. In addition, we add an af:clientAttribute with the name ‘columnName’ which we pass the EL of the af:column headerText property.

Next, we add an af:resource component to the af:document where we specify the JavaScript for the clientListener method ‘clientCellSelectionCall’. We use a JavaScript file to code the method. We could have added the method to the page directly, but if we want to reuse the pattern, it’s better to use a JavaScript file

The file is located in the public_html folder (Web Content) in a subdirectory ‘javascript’

The method code is

The click event on the af:outputText component triggers a call to the javascript method ‘clientCellSelectionCall’ (via the clientListener) with the source of the event, the af:outputText component. The method reads the clientAttribute added (line 3) and calls the serverListener of type ‘cellSelection’. This event is defined by the af:serverListener on the af:outputText. The component which triggered the event and the column name added as client attribute are passed to the serverListener.

The serverListener is a bean method defined in a request scope bean on the af:outputText component as

method="#{TableCellSelectionBean.handleTableCellSelection}"

In the bean, the method looks like

public void handleTableCellSelection(ClientEvent event) {
  // get payload which is the ui component which fired the event
  UIComponent ui = (UIComponent)event.getParameters().get("payload");
  // get the column from the event which is sent too
  String column = (String)event.getParameters().get("column");
  RichOutputText rt = (RichOutputText)ui;
  // get current row key
  DCBindingContainer bindingContainer = (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
  DCIteratorBinding binding = bindingContainer.findIteratorBinding("EmployeesViewIterator");
  Row currentRow = binding.getCurrentRow();
  Key key = currentRow.getKey();
  // compile info about clicked cell
  String out = "Payload:" + ui + "
  column: "+ column + "
  val: " + rt.getValue() + "
  key: "+key.toString();
  logger.info(out);
  setCellInfo(out);
}

Here we get the component which triggered the event (as payload) and the name of the column. Using this information we can get e.g. to the value of the column (via the UI component). The row of the cell we get via the current row of the iterator. With this information, we get the key of the row. We can get much more information here, like historical data about the current employee’s salary, if the salary cell was clicked.

We just create a string from the information which we show in the UI to the user

Here are some images of different cells clicked in the UI:

Download

You can download the sample, which was built using JDeveloper 11.1.1.9, from GitHub BlogTableCellSelection. The sample uses the HR DB schema.

JDeveloper: Skin Radio Buttons

In this blog article, I like to share how to use a skin to alter the look of radio buttons in ADF. The use case was a question on the ODC space JDeveloper & ADF which asked about how to provide more space for the radio buttons.

Here is an image of the default and the resulting radio buttons:

As you see, in the first radio group the space between the selectItems is narrower than in the second group.

In my older post about JDeveloper: Advanced Skin Technique I showed how to find out which style to change, so I spare this here.

The image above shows the standard “radiogroup” in Chrome Developer Tools. As you can see the radiogroup consists of “div” elements, each specifying one of the selectItem.

To change the spacing, we add a style class to the skin file like

.mysor af|selectOneRadio::content div {
  padding: 0px 0px 10px 0px;
}

The “.mysor” is the name of the style class which we later use on the page. The magic is done by specifying the base style as af|selectOneRadio::content and from there style each “div” element having the base style as a parent. This way we style the blue marked div in the image above.

One question remains. Why do we use a skin and don’t add the code right into the page?

Well, using a skin is the preferred method. The skin is created once and can be used everywhere in the application. If you need to make changes, you don’t have to search for the pages where the style has been added, but you just change the skin file and you are done.

Download Sample

You can download the sample which is build using JDev 12.2.1.2.0 and uses the HR DB schema from GitHub BlogAdvancedSkin

 

 

Train Stop Status Handling

A question on the Oracle Developers Community was about how to handle a train stops visited status.

Use Case

The use case behind this was that a train can be used as a workflow visualization. A normal user starts the train, but at one point a manager has to approve something. This approval is one or more stops on the same train. If the manager picks up the workflow he should automatically start with the approval stop. There is no need for him to see the data accumulated in the stops before.

The use case has multiple challenges:

  1. Securing train stops for different user roles
  2. Allow starting the train from any stop
  3. Handling the state of the train stops

The first two challenges are handler by All Aboard, 97. How-to defer train-stop navigation for custom form validation or other developer interaction, and 82. How to programmatically navigate ADF trains.

The missing part is how to handle the train stops ‘visited’ state (see image above). If you start the train directly with ‘Stop 3’ you get this state

UI

To implement this use case, we use a simple UI. It contains an input field, a button and the train which is added to the page as a region.

In the input field names label 1 you can enter the stop where the train should start. If no number is given, the train starts with the first stop. We use this input field to mimic the different starting stop for different users. This is the page when we start the application:

This is the page when we start the final application:

You can navigate between the train stops by using the ‘Back’ and ‘Next’ button, or by clicking the next stop in the train bar. As the stops are set to sequential, you can’t directly click on the 4th stop. You have to go through the stops 1 to 3 first.

Enter a number between 1 and 5 into the input field and tab out of the field will set the parameter for the train task flow and restart the task flow. The navigation is done via a router in the task flow. In the image below the stop number 3 is set as the starting stop for the train

And as you see the stops 1 and 2 are looking like they have visited before.

Implementation

To show how to implement this we start with a simple bounded task flow which builds the train

The start builds a router which we use to navigate to the stop where we want to start the train. The starting stop is passed as parameter to the task flow

In the router, which is marked as default activity, the parameter is used to execute the navigation

The Magic

If you look at the train stop properties in the properties inspector you’ll notice, that there is no property for the visited state

This option is not available in the UI. Oracle has missed or deliberately missed to make this property accessible via the properties. If you dig into the implementation of the train task flow (see the articles provided at the begin of the blog), you’ll see how to access the train and its stops by code:

ViewPortContext currentViewPortCtx = controllerContext.getCurrentViewPort();
TaskFlowContext taskFlowCtx = currentViewPortCtx.getTaskFlowContext();
TaskFlowTrainModel taskFlowTrainModel = taskFlowCtx.getTaskFlowTrainModel();
// get the stop from the map
TaskFlowTrainStopModel currentStop = taskFlowTrainModel.getCurrentStop();

The TaskFlowTrainStopModel doesn’t provide any access to the visited state. If you look at the class definition you’ll notice, that it’s only an interface

which doesn’t provide access to the visited property. Setting a breakpoint in the debugger we can inspect an instance of this interface

and we get the class implementing the interface as:

 oracle.adfinternal.controller.train.TrainStopModel

This class has the visited property we are looking for.

Solution

Now we can implement a method which we call before a train stop gets rendered and which sets the visited property of all previous stops to true.

CAUTION

THIS IN AN INTERNAL CLASS WHICH YOU SHOULD NOT USE!

However, it’s the class we need to get to the property. You have to understand, that the usage of the class has its risks, but that it’s not forbidden. The risk is that Oracle can change or delete the class without notifying you beforehand. So, in later versions, your code might break.

The method checks the task flow parameter if it’s null to set to a number less or equal to 0. In this case, the method returns an empty string. We do this check to avoid that the method does it’s work every time we navigate the train. It should be done only once when the train starts.

If the check finds a positive number, it sets the task flow parameter to zero (line 37).

It then gets the task flow information from the Context (lines 39-43). In line 50 we acquire the current stop before we loop over all previous stops and set their visited property to true (lines 53-59).

The missing part is how to call this method when a train stop is rendered. For this, we use a technique called Lazy Initalizing Beans. The trick is to use a hidden af:outputText and set e.g. the value property of the component to a bean property.

When the page or fragment is rendered, the method getInitStatus() in the bean is called. This is exactly the method shown above. We add this hidden af:outputText to each train stop before the af:train component.

Sample

You can download the sample from GitHub BlogTrainStopStatus. The sample is build using JDev 12.2.1.3 and doesn’t need a DB connection. You can use the same technique in other JDeveloper versions.

Query and Filter an af:listView

Most of the time we use tables to show tabular data to users. However, JDev and ADF allow for other components like the af:listView to be used to show such data to the user in a more modern way.

The image above shows the normal display of data when an af:query is used together with a table to show the result.

A more fancy, modern look we get if we use a af:listView to show the results as this allows us to style the data

Use case 1

We like to use an af:query to search for employees and show the result in a styled af:listView.

Implementation 1

This is pretty easy as we only have to use an af:listView as the result component of the af:query

And to exchange the af:table with an af:listView. Or you build the page by first dropping an af:query onto the page (without table) and then add the af:listView

Then you get the wizard to layout the list

This will give you a basic layout which can be styles in JDev as

The final result is

which looks more modern. One thing the af:table give you out of the box is the second use case.

User Case 2

We like the af:listView to be able to be filter the result like the af:table can.

Implementation of second use case

Easy you think? Well, the af:listView component doesn’t provide any filter out of the box. There isn’t even a filterModel like there is for an af:table.

So, how do we get this implemented. The idea is to use a af:table component but only use the filter provided by the af:table. The remaining parts like table data, possible scroll bars and status bar or scrollbars we remove.

We start by dragging the EmployeesView1 from the data control onto the page again.

And drop it after the closing af:panelHeader and before the af:listView as ‘ADF Table’

In the image you see that I have removed some available columns. Before we go to hide the part of the table we don’t need, we make the table work together with the af:query and the af:listView. When we use the af:query the table shows the right detail (auto PPR triggers the refresh of the table). However, if you have queried for the ‘Purchasing’ department and then enter an ‘s’ into the ‘First Name’ filter field of the table and hit enter, you get

As you see, the table shows the right result (2 rows) but the listView still shows all employees of the Purchasing department.

To make it work, we need to add a partialTrigger to the listView which points to the table. This way each time the table changes the listView will too.

Save all changes and refresh the page. Now if you enter a value into a filter field and hit enter, the listView will update too.

After the page works we have to get rid of the data below the header of the table. This is easy to accomplish by styling the table. We only need the filter field and the header below the filter fields so that we know which field filters which data. Simply set the maxHeight of the table to the exact height of the the two components. You can use your browser’s developer tools (F12) to measure the height. In my sample it’s 65px. So, setting the tables inlinestyle to

max-height: 65px;

will hide everything below the filter and the header

If you like you can create a skin and create a style class and use this style class instead of setting the max-height directly to the inlineStyle of the table. A nice addon is that the table header sorting is working too for the listView.

You can download the sample from gitHub BlogFilterListView. The sample is build using JDev 12.2.1.3 and uses the HR DB schema. The principle can be used in other JDev versions too.

Using External REST Services with JDeveloper Part 3

In this blog we look how we can use an external REST service with JDev 12.2.1.2. To make things more interesting we don’t use an ADF based REST service and we look how to get nested data into the UI.

For this sample we like to create an application which allows to search for music tracks and show the results in a table or listview. To get the music data we use a REST service and to display the data we use ADF faces application.

In Part 1 we create the application and the project for the REST Data Control. In Part 2 we started creating the UI using the REST Data Control. In this final part we are enhancing the UI by using nested data from the REST Web Service and add this as column to the search result table. Before we start we look at the use case again.

Use Case

Before we begin implementing something which uses the external REST service we have to think about the use case. We like to implement a music title search using the external MusicBrainz REST service. A user should be able to enter a music title or part of a music title and as a result of the search she/he should get a list of titles, the artist or artists, the album and an id.

 

Handling nested Data

The use case demands that we add the artist and the album the music track is on to the same table. A look at the table in it’s current layout, make this understandable.

First of all we need to identify the dat a we want to add to the table in the response we get from the service.

Let’s investigate the JSON data, part of it, we get from the service for the search for the track ‘yesterday’


 

{
   "created": "2017-08-02T12:42:48.815Z",
   "count": 5985,
   "offset": 0,
   "recordings": [
       {
           "id": "465ad10d-97c9-4cfd-abd3-b765b0924e0b",
           "score": "100",
           "title": "Yesterday",
           "length": 243560,
           "video": null,
           "artist-credit": [
               {
                   "artist": {
                       "id": "351d8bdf-33a1-45e2-8c04-c85fad20da55",
                       "name": "Sarah Vaughan",
                       "sort-name": "Vaughan, Sarah",
                       "aliases": [
                           {
                               "sort-name": "Sarah Vahghan",
                               "name": "Sarah Vahghan",
                               "locale": null,
                               "type": null,
                               "primary": null,
                               "begin-date": null,
                               "end-date": null
                           },
...
                       ]
                   }
               }
           ],
           "releases": [
               {
                   "id": "f088ce44-62fb-4c68-a1e3-e2975eb87f52",
                   "title": "Songs of the Beatles",
                   "status": "Official",
                   "release-group": {
                       "id": "5e4838fa-07f1-3b93-8c9d-e7107774108b",
                       "primary-type": "Album"
                   },
                   "country": "US",

I marked the info ne need in blue in the data above. We see that the artist name is inside a list of name ‘artist_credit’ and that there can be multiple artists inside the ‘artist_credit’. This is a typical master/detail relationship.

The same is true for the album name which is an attribute inside a list of ‘releases’. The big question now is how do we get the nested data into the table as column.

When we expand the MusicBrainz Data Control we see the same structure we saw in the JSON data

So, the data is there, we only need to get to it. The data is structured like a tree and ADF is capable of accessing data in a tree structure (e.g. using an af:tree component). However, we like to use a simple table and don’t want to use a af:tree or af:treeTable. To get to the data, we first have to add the nested structure to the recordings binding we already use to display the current two columns of the table.

Right now we see the first level of the tree, the ‘recodrings’. Click the green ‘+’ sign to add the next level ‘artist_credit’

Add all attributes to the right side

As the artist name is still one level down, click the green ‘+’ sign again and add the ‘artist’ level

And shuffle the id and name attribute to the right side

Finnally we need to add the ‘releases’ level to get to the album name. For this select the ‘recordings’ level (the first) and click the green ‘+’ sign

And shuffle the id, title and track_count to the right side

Now all related data we need can be accessed via the ‘recordings’ binding.

We start with the artist column. Select the af:table in the structure window and open hte properties window

Click the green ‘+’ sign twice in the columns section to add two columns

Select the first added column (score in the image) and change the display label to ‘Artist’ and the component To Use’ to ‘ADF Output Text’. The second added column we change the display label to ‘Album’ and the ‘Component To Use’ again to ‘ADF Output Text’

We change the ‘Value Binding’ in the next step.

To get to the data for the artists we need to traverse two levels of sub rows. First level is the ‘artist_credit’, the second level is the artist itself. Here we have to keep in mind, that there can be more than one artist. In this case we have to join the names into one string for the table. As the ‘artist_credit’ itself can occur more than once, at least that’S what the data structure is telling us, we use an iterator to get the data.

The value property points to the current row and selects the ‘artist_creadit’. Each item we get from this iterator we access via the var property. So the item inside the iterator can be addressed as ‘artists’.

The artists can be one or more so we need another iterator to get to the artist data.

<af:iterator id="i2" value="#{artists.artist}" var="art" varStatus="artStat">

The value property for this iterator points to the artist we got from the outer iterator and is addressed as #{artists.artist}. To access attributes inside the artist data structure we use the var property and set it to ‘art’.

Now we have to somehow joint multiple artist names together if a track has more than one artist. The MusicBrainz Web Service helps us here by providing a ‘joinphrase’ which can be used to build one string for all artists. This ‘joinphrase’ can be .e.g a ‘&’ or a ‘,’. The full column code for the artist looks like

<af:iterator id="i2" value="#{artists.artist}" var="art" varStatus="artStat">

Here is some sample data for a search for the track ‘Something Stupid’ (to make it more readable I removed some attributes

"recordings": [
 {
  "title": "Something Stupid",
  "artist-credit": [
   {
    "joinphrase": " duet with ",
    "artist": {
     "name": "The Mavericks",
    }
   },
   {
    "joinphrase": " & ",
    "artist": {
     "name": "Raul Malo",
    }
   },
   {
    "artist": {
     "name": "Trisha Yearwood",
    }
   }
 ]

This data will be translated into the artist: “The Mavericks duet with Raul Malo & Trisha Yearwood”.

For the album column it’s easier. This too needs an iterator, but we don’t have to go down another level and we don’T have to join the data we get from the iterator. The column code for the album looks like

<af:iterator id="i1" value="#{row.artist_credit}" var="artists">
 <af:iterator id="i2" value="#{artists.artist}" var="art"
                    varStatus="artStat">
   <af:outputText value="#{art.name}#{artists.joinphrase}" id="ot5"/>
 </af:iterator>
</af:iterator>

The whole table for the search results look like

With this the page is ready and we can run the application. After start we see the page

Now entering a search term ‘something stupid’ into the search field will show

or trying the search with ‘dave’ will show

This concludes this mini series about how to use external REST Services and build an ADF UI from it.

The source code for this sample can be loaded from GitHub BlogUsingExternalREST. The sample was done using JDeveloper 12.2.1.2 and don’t use a DB.

Using External REST Services with JDeveloper (Part 2)

In this blog we look how we can use an external REST service with JDev 12.2.1.2. To make things more interesting we don’t use an ADF based REST service and we look how to get nested data into the UI.

For this sample we like to create an application which allows to search for music tracks and show the results in a table or listview. To get the music data we use a REST service and to display the data we use ADF faces application.

In Part 1 we create the application and the project for the REST Data Control. In Part 2 we start create the UI using the REST Data Control. Before we start we look at the use case again.

Use Case

Before we begin implementing something which uses the external REST service we have to think about the use case. We like to implement a music title search using the external MusicBrainz REST service. A user should be able to enter a music title or part of a music title and as a result of the search she/he should get a list of titles, the artist or artists, the album and an id.

Implementing the UI

In Part 1 we implemented the REST Data Control which we now use to build a small UI. Let’s look at the REST Web Service Data Control in the JDeveloper IDE

Above we see the data control ‘MusicBrainzJSONDC’ with it’s only resource recording, the input parameter names ‘query’ and the return data structure which was created using the sample JSON data we used when creating the REST Web Service Data Control.

When we query the resource we get back a complex data structure which give us information about how many results where found for the query and a list of ‘recordings’ which holds the artist names and the album names as ‘releases’.

To build the result table which should show the title id, the artist or artists and the album we have to go through all the nested data.

Setting up the search page

We start by adding a view the unbounded task flow adfc-config.xml which we name ‘MunicBrainz’ and create the page with a quick layout from the list

Make sure that you have selected to use ‘Facelets’! This will create a starter page with the layout selected. When the page is created it opens up in JDev like

We add an outputText component to the header and set the value to ‘MusicBrainz Test’

The resulting code looks like

For the layout we want to archive (search part and table to show the results) we need another grid row in the panelGridLayout. We drag a GridRow component from the ‘Component palette’ onto the panelGridLayout component in the structure window. You can use the source window too if you like. Dropping a new gridRow in the design isn’t recommended as it’s difficult to control the point where to insert the component.

Now we adjust the height of the rows and set the first row to 50 pixel, the second one to 100 pixel and leave the remaining height to the third gridRow:

Next we add the panelFormLayout holding the search field and the button to search for music tracks. For this we simply drag the ‘recording(String)’ operation from the MusicBrainzJSONDC data control onto the second grid row and drop it as ‘ADF Parameter Form’

we get a dialog showing us the methods parameter. Here we can bind the field to any other data field we like. However, in this case we leave it as is and just click OK

The framework wires everything up for us and we get the page as

Here we change the text on the button to ‘Search’

To see how things are wired up we look at the pagedef for the page

Here we see the method ‘recording’ and can expand it by clicking on the pencil icon

Where we see the details like where the parameter ‘query’ gets it’s value from (#{bindings.query.inputValue}). The ‘query’ binding is defined right above the recording method:

When we select the binding for ‘query’ wee see that the binding points to a variable defined in the pagedef (see Creating Variables and Attribute Bindings to Store Values Temporarily in the PageDef) which holds the value the user enters into the field. The recordings binding and the other stuff we talk about later.

Next up is creating the table with the results returned from the method call. For this we drag the recordings from the methodReturn binding onto the page and drop it as ADF Table into the third gridRow

To get the next dialog

Where we remove every attribute but the ‘id’ and the ‘title’ by selecting the rows and clicking the red ‘x’ icon. We set the row selection to single and make the table ‘read only’

The resulting page looks like

If we run the application now the UI comes up, but we’ll get an exception

Why’s that?

If we look into the servers log we see the error:-


<oracle.adf.view> <Utils> <buildFacesMessage> <ADF: Adding the following JSF error message: JBO-57001: Invocation of service URL used in connection failed with status code 400 Unable to parse search:tnum:.> 
oracle.adf.model.connection.rest.exception.RestConnectionException: JBO-57001: Invocation of service URL used in connection failed with status code 400 Unable to parse search:tnum:.
    at oracle.adf.model.connection.rest.RestConnection.getResponseCheckingStatus(RestConnection.java:783)
    at oracle.adf.model.connection.rest.RestConnection.getResponse(RestConnection.java:629)
    at oracle.adfinternal.model.adapter.ChildOperation.getJerseyResponse(ChildOperation.java:1167)
    at oracle.adfinternal.model.adapter.ChildOperation.makeServerCall(ChildOperation.java:977)
    at oracle.adfinternal.model.adapter.JSONChildOperation.invokeOperationInternal(ChildOperation.java:2056)
    at oracle.adfinternal.model.adapter.ChildOperation.invokeOperation(ChildOperation.java:542)
    at oracle.adf.model.adapter.rest.RestURLDataControl.invokeOperation(RestURLDataControl.java:247)
    at oracle.adf.model.bean.DCBeanDataControl.invokeMethod(DCBeanDataControl.java:512)
    at oracle.adf.model.binding.DCInvokeMethod.callMethod(DCInvokeMethod.java:269)
    at oracle.jbo.uicli.binding.JUCtrlActionBinding.doIt(JUCtrlActionBinding.java:1742)
    at oracle.adf.model.binding.DCDataControl.invokeOperation(DCDataControl.java:2371)
    at oracle.adf.model.bean.DCBeanDataControl.invokeOperation(DCBeanDataControl.java:628)
    at oracle.adf.model.adapter.AdapterDCService.invokeOperation(AdapterDCService.java:316)
    at oracle.jbo.uicli.binding.JUCtrlActionBinding.invoke(JUCtrlActionBinding.java:803)
    at oracle.jbo.uicli.binding.JUMethodIteratorDef$JUMethodIteratorBinding.invokeMethodAction(JUMethodIteratorDef.java:175)

 


Which doesn’t tell us more. What we see is that an ‘invokeMethod’ is the root cause. The reason is that when the pages loads, the iterators in the executable section of the pagedef are fired. As we saw we have two executables and those are giving us the errors.

As the field is empty the recordings method is called without a query parameter. If you mimic this in Postman with the query

http://musicbrainz.org/ws/2/recording/?fmt=json&query=

we get

Exactly the same error, only this time as html.

To solve this problem we have to avoid calling the service without a parameter. This can easily be archived by adding an expression to the executable RefreshCondition property

This we have to both executables in the pagedef. After that running the application will get us

 

This ends part 2 of this series, due to the length and the number of images in this post. The remaining part 3 will cover how to use the nested data and to add it to the search result table and provide the link to the sample application.

Blog Using External REST Servies (Part 1)

Using External REST Services with JDeveloper 12.2.1.2 (Part 1)

In this blog we look how we can use an external REST service with JDev 12.2.1.2. To make things more interesting we don’t use an ADF based REST service and we look how to get nested data into the UI.

For this sample we like to create an application which allows to search for music tracks and show the results in a table or listview. To get the music data we use a REST service and to display the data we use ADF faces application.

In part 1 we create the application and the project for the REST Data Control. Part 2 we will create the UI using the REST Data Control.

Setting up an external REST services

Let’s start be selecting a REST service which is available for public use without the need to get a key first. We use such a service to make it easier for you to run the sample and to look at the code. If we would need a key to use the API, you would need to register yourself with the service before you can run the sample.

There are a couple of such REST services like Spotify, iTunes or MusicBrainz which offer search APIs for music data as public REST service. Spotify we have to eliminate from the list as this service requires an API key since Mai 2017, meaning that it’s not public available without you register yourself before using it. ITunes REST API allows public access and the data structure returned is very simple. The result for a search get you everything in a flat structure. This will make things easy, too easy 🙂

For this sample where we like to show how to work with more complex data structures returned by a REST service. So, the final vote for this blog goes to MusicBrainz (MusicBrainz Rest API).

MusicBrainz

Musicbrainz REST API comes in different versions (V1 and V2). The current version v2 is what we are interested in as V1 is already deprecated. The documentation tell us, that the service is an XML style REST service. However, there is a JSON style REST service available too. This JSON style RSET service is what we use for the sample.

Before we implement the REST service calls we need to find out how to search for the data we like to show. For this a tool like Postman is a great help. Postman allows you to enter calls to REST services in a browser like UI. You can set all kind of headers, e.g. below we see a sample of the Postman UI (in the result a couple of sub structures are folded to show the relevant data). The query searched for recordings named ‘yesterday’ and asked for a result in JSON format:

To learn more about the possible searches refer to Web Service Search.The data structures and their meaning are described in in the MusicBrainz Data Structure.

Use Case

Before we begin implementing something which uses the external REST service we have to think about the use case. We like to implement a music title search using the external MusicBrainz REST service. A user should be able to enter a music title or part of a music title and as a result of the search she/he should get a list of titles, the artist or artists, the album and an id.

Creating a REST Web Service Project

After we looked at the REST Service and the data it returned we have identified the data we need to get from the REST service. The first step is to create a project which communicate with the REST service.

We create a normal Fusion Web Application which will create a ADF model project and a view controller project. If you need a script on how to do this you can look at Writing Reproducible Test Cases: Why and How. The model project we don’t need for this sample. You can delete it or just leave it empty.

For the access to the MusicBrainz data we create a new REST Web Service Project inside the application:

Name it and go through the rest of the wizard

Before we create the web service data control, we need to create a REST Connection from the resource pallete we create a new IDE connection of REST type

Then we later need data returned from the REST service which the wizard uses to produce the data structure. A simple way to get such data is to use e.g. Postman to call the REST service:

Copy the result (all of it!) and save it to a file. Next we create a new Web Service Data Control from the gallery

Select the ‘WebService Data Control (SOAP/REST)’

And fill out the wizard. Select the REST connection created before

In the next image click on the green ‘+’ sign

And change the path to ‘/ws/2/recording’, select JSON as data format and checkmark the GET method to enter ‘recording’ into the field.

In the next screen we need to select ‘Parse from Sample Code’ and copy the content of the file we saved from Postman into the textarea

And finally test the Web Service Data Control

The finish the wizard. Now we can test the data contron by finding the DataControl.dcx file in the project and right click on it. Choose ‘Run’ from the context menu:

In the dialog window right click hte data control and choose ‘Operations’

Fill in the fields and click the execute button

The result should look like

You can copy the return value into an editor to fully see it. If you don’t get the successful result, check the steps against the ones in the blog.

This concludes part 1 of this series. In part 2 we develop the UI for the application using the Web Service Data Control we created in this part. The source of the sample can be downloaded from GitHub. The link to it will be provided with part 2.