Monday, November 21, 2016

Private Application Deployments in Oracle Process Cloud Service - New Feature!

The latest Oracle Process Cloud Service (PCS) brought finer control with respect to deployment strategies with the introduction of "Private" deployments, an entirely new feature that allows you to define deployment permissions on individual environments.

Previous versions of Oracle Process Cloud Service allowed the developer to not only test their applications, which basically does a deployment to a sandbox environment, but to also deploy applications to configured targets.

The latest Oracle Process Cloud Service allows you to define a more fine grained deployment strategy, thus restricting developers from deploying applications and only granting this privilege to a user with administrative permissions.

What is even more interesting is that this configuration can be performed for each target. So for example, you might have different environments, DEV, TEST and PROD and only allow developers to deploy on DEV.

To configure the deployment permissions, from the Composer Home page click on "Management". You will notice that for each server there is a drop down with the default selection set to "Private". This denotes that only administrators can deploy applications to that server.

Use the drop down list and select the "Open" deployment option to allow both administrators and developers to deploy to the selected target.


Monday, November 14, 2016

Event Based Gateways and Correlations in Oracle Process Cloud Service

The latest Oracle Process Cloud Service release in September 2016 (v16.3.5) added the support of two important functionalities; the "Event Based Gateway" for process branching and "Correlations" for process communication.

These capabilities have been available for quite some time in Oracle's Process Cloud Service counterpart, the Oracle BPM Suite and have been described in detail in two of my blog posts; "Correlations in Oracle BPM 12c" and "Oracle BPM 12c Gateways (Part 5 of 5): Event-based Gateway".

Even though the functional concept is the exactly the same, whether used in an Oracle BPM Suite process or an Oracle Process Cloud Service process, there are yet some small differences, especially with the "Event Based Gateway" in Oracle Process Cloud Service.

So in this blog post we will see, in detail, how you can use the "Event-Based Gateway"to implement divergence and branching in your processes using events generated from external processes. Process communication will be implemented using "Correlations".

The scenario that I will use is quite simple and I will use two processes. The first process will simulate a warehouse inventory process that depending on the order id (supplied as a process request argument) will respond whether the stock item is available or not.

The second process will invoke the "Warehouse Inventory" mockup process using a custom correlation key and will make use of the "Event Based Gateway" to pick the generated event.

So let's start with the implementation of the "Warehouse Inventory" mockup process. Create a new application in Oracle Process Cloud Service, give it a name and file it under a space (I've named it "EventBasedGatewayAndCorrelationsDemoApp" under my personal space).

Next create a new process using the "Message" pattern

Next we will create the "Warehouse Inventory" process. From the "Create a Process" screen, select the "Message" pattern, give your process a name and click on "Create".

Edit the "Start" component, edit the interface by clicking on the "Edit" button next to the "Define Interface" type to add a new request argument called "orderId" of type string.

The "Warehouse" process, depending on the supplied order id will respond back to the caller using a different end message component. But let's first configure the default "Message End" component.

Edit the default "End" component and add two string response arguments, "orderId" and "status" and change the default operation name to "endWithNo". Change also the default label from "End" to "End with NO" (to distinguish between the two operations from the calling process).

Add another "Message End" component and again create two string arguments, "orderId" and "status" and change the default operation name to "endWithYes". Change also the default label to "End with YES".

We will need one process data object to store the incoming order id and pass it back to the response. So click on the "Data Objects" and create a new data object called "orderId" of type string.

Next assign the process input order id argument to the order id process data object. On the "Start Message" select "Open Data Associations" and drag the orderId input argument to the "Start" association input box. Expand the "Process Data" and drag the orderId process data object to the "WarehouseProcess" association input box.

Now that we have the process data objects defined, we can process with providing the data associations on the two "Message End" components. Therefore open the data associations of the "End With YES" task and map the order id process data object to the orderId response argument and a static string (let's say "YES") to the status response argument.

Do the same thing with the "End With NO" task but this time mapping a different static string to the status response argument (for example "NO").

Next we will add an "Exclusive Gateway" between the "Start" and default end message component (if you followed my instructions it should be the "End with NO" message end component). Optionally rename the default "Exclusive Gateway" label to something more meaningful (for example, "Stock is Available?") and add a conditional flow from the "Exclusive Gateway" to the second end message component ("End with YES"). For better readability of the process you can add labels to the default and conditional flows.

If you click on the "Validation" button you should notice that there is a validation error. That's because we have created a conditional flow with an empty condition. So open the conditional flow and define a condition (for example, take that path if the orderId is "123").

Our "Warehouse Inventory" mockup process is now complete. We can now move on with creating our main process, the process that will be calling the "Warehouse Inventory" process.

Create a new process using again the "Message" pattern (I've named this new process "OrderProcess").

This new process will accept and order id and will return a status (both arguments will be of type string). Therefore on the "Start" message component, go its properties, click on the "Edit" button next to the "Define Interface" implementation and create a string argument called orderId.

Using the exact same steps, create a "status" response argument on the "End" message component.

Both arguments will have to be carried along the main process, therefore create two new data objects, using the same names and types.

Just like we did with the "Warehouse Inventory" process, we need to assign the request argument to its respective process data object so that it can be used along the process. So open the "Start" data associations and drag the orderId input argument to the "Start" association input box. Expand the "Process Data" and drag the orderId process data object to the "OrderProcess" association input box.

Using the same approach, we need to map the "status" process data object to the response argument. Open the "End" data associations, expand the "Process Data" and drag the status process data object to the "OrderProcess" association input box. drag the status output argument to the "End" association input box.

We will be invoking the "Warehouse Inventory" process using a "Message Send" component and we will be using the new correlation capabilities support in Oracle Process Cloud Service to define the conversation association between the calling and callee process.

Drag and drop a "Message Send" task between the "Start" and "End" tasks and name it "Invoke Warehouse Process". Open its properties and from the "Type" drop down select "Process Call". Click on the "Edit" pencil button and from the "Process" search box select your "Warehouse" process. The "Target Node" should be automatically populated with the "Start" message.

If you recall, the "Warehouse" process requires an order id to be passed as input. So open the "Message Send" data associations and map the orderId process data object to the orderId send task argument.

Drag and drop an "Event Based Gateway" just after the "Invoke Warehouse Process" send message task and name it "Catch Warehouse Event". Delete the default sequence flow from the "Event Based Gateway" to the "End" task and add two "Message Catch" events and name them "Catch No Event" and "Catch Yes Event" respectively. Add a default sequence flow from the "Event Based Gateway" to the two new "Message Catch" tasks and add a default sequence flow from each of the two "Message Catch" tasks to the "End" task.

We need to define the implementation details of each of the "Message Catch" events. Go to the "Catch No Event", open its properties and from the implementation type drop down select "Process Call" and click on the "Edit" pencil button. From the "Process" search box select your "Warehouse" process and in the "Target Node"select the "End with NO" end message.

The "Warehouse" process, depending on the order id will return a different status (mapped via it's status response argument). So go to the data associations of each of the "Message Catch" tasks and map the status response argument to the status process data object.

The only thing left before we deploy and test our processes is to define the correlations between the calling process (OrderProcess) and callee (WarehouseProcess). Custom correlations, also known as "message-based" correlations enables the definition and use of "business-friendly" information carried as part of the message payload to be used to uniquely identify and associate a message with a conversation. This type of correlation enables the definition of multiple attributes referred to as "Correlation Properties" into various correlation sets know as "Correlation Keys".

We will be using only one correlation property and that will be the order id. Click on the "Correlations" button (located above your process on the button toolbar), create a new correlation key and a new string correlation property called orderId. Please make sure you shuffle the correlation property to your correlation key, otherwise you will not be able to use it.

With custom correlations you have the concept of an initializer, the task that set's up the message association agreement and we also have the notion of a correlator, tasks that wait to receive a message using the correlation definition instantiated by the initializer.

In our case the initializer will be the "Message Send" task while the two "Message Catch" tasks will be the correlators. So go the "Invoke Warehouse Process" message send properties, select "Correlations" and click on the "Add" button to add the correlation key you created in the previous step. It should automatically detect the orderId correlation key property. You just need to assign a value to it and this will be the order id process data object.

On each of the "Message Catch" tasks, go to "Properties", then "Correlations" and make sure to switch to the "Correlate" tab and add your correlation key. Again assign the orderId process data object to the orderId correlation property.

One last step before we can deploy is that we have to publish our work. So click on the "Publish" button and in the "Publish Application" popup add a comment and click "Publish".


We are now ready to deploy and test our application. Click on "Deploy" and select "Deploy new version". In the "Select Version" train stop select "Last Published Version" and click "Customize". Leave all defaults on the "Customize" screen and click on the "Validate" button. Ensure that your application is successfully validated and click on "Options". Set a revision id and click on "Deploy".

Since our main order process can only be started using a message, we need to get the endpoint URL and invoke it via SoapUI. To do so click on the "Management" link, locate your application from the list of deployed applications and scroll to the right. Click on the "Actions" button and select "Web Services".

You should have two endpoint URLs, one for the order process and one for the warehouse process. Ensure you copy the order endpoint and using SoapUI invoke an instance of the order process. I will go with the happy path so I've enter order id "123" (please note that you will need to pass your credentials and a timestamp in the header, otherwise you will get a security exception from Oracle Cloud).

From the Oracle Process Cloud Service dashboard click on the "Track Instances" banner to go to instance tracking. Ensure from the filters you've selected "Completed". You should see two instances completed, one from the "Warehouse Process" and one from the "Order Process".

Go to the details of the "Order" process (click on the green arrow) and expand the history view. You should see that the order process followed the "happy" path.

Invoke the process again this time providing an different order id. Go to instance tracking and again you should see a pair of instances. Open the "Order" instance details and you should now see that the process followed the alternative path.


Monday, October 24, 2016

REST Service Producing JSON & XML Response Bug and Fix in JDeveloper 12.2.1

I recently came across a very nice requirement where a REST service was required to produce a response both in JSON and XML format.

However, there is a bug with JDeveloper and the automatic generation of EJB/TopLink Entity annotations. This bug is reproduced when you choose to generate a REST service on that automatically generated EJB entity and you choose to produces both a JSON and an XML response.

What's even trickier is that this bug is only revealed at runtime when you choose to parse an XML response. It will throw an Internal Server Error (500) and if you inspect the log files you will see the following trace:

MessageBodyWriter not found for media type=application/xml, type=class java.util.ArrayList, genericType=java.util.List

So let's see in details how to reproduce this bug and how to fix it.

I will create a new application using the "Custom Application" template and will provide an application (bug-with-rest-service-app) and a project name (bug-with-rest-service).

What I will do is that I will create an EJB entity based on the "Countries" table from the HR sample database schema. So right-click your project, choose "New", "From Gallery" and under the "Business Tier" section, select the "EJB" category and then from the category items select "Entities from Tables".

Ensure "JPA 2.0 Entities (Java EE 6)" is selected and click next. Click "Next" in the "Persistence Unit" and "Types of Connection" steps and in the fourth step ("Database Connection"), click on the green plus button to create a new database connection (or choose an existing one from the drop down list).

In the fifth step select the "Countries" table and click "Next".

Specify an appropriate package name for creating the EJB entity and click "Next" and then "Finish".

You should have an offline database created with the "Countries" table, a persistence.xml file (JPA configuration file) generated under "META-INF" and your "Countries" EJB entity created under your defined java package path.

Next we need to create a facade and expose the methods that we want to expose on the "Counties" EJB entity. To do that we will use another JDeveloper wizard.

So right-click your project, choose "New" and from the context-menu select "Java Service Facade (JPA/TopLink). Specify a package for storing your facade and click "Next".

Leave all defaults on the second step and click "Next" and on the third step of the wizard click on "Finish".

So now we have a Facade which acts like our "controller", defining what is accessible on the "Countries" EJB entity and you should have also a test client which via the facade accesses one of the exposed operations (should be getCountriesFindAll).

If you run the test client you should get a list of countries printed in the log window.

We are now ready to create our REST service. Again for this we will use JDeveloper's REST build in capabilities to generate a REST service.

There are several ways to do that. We can very just right click our facade and create a REST service. However, this would result in a really bad design pattern. I highly recommend that you create a "wrapper" class on top of the facade and then expose that "wrapper" class as a REST service.

So right click your project, select "New" and select "Java Class". Give your Java class a name, specify a package and click "OK".

Create a method in your new class that just returns a list of counties using the facade class that you generated before.

We are now ready to create a RESTful service using the above class. To do so, right click your Java class and from the context menu select "Create RESTful Service". We only need to configure step 3 of the wizard.

You should have your "getAllCountries" method listed under the "Configure HTTP Methods" section.

In the "Type" field select the "GET" operation and click in the "Produces" field to open the "Media Types" popup and select the "application/json" and "application/xml" media types (so that our service is capable of returning either a response in JSON or XML format).

Click "Finish" to generate the REST service (ignore the return type warning).

If you inspect your Java class you should notice that it has been "decorated" with various annotations to instruct the runtime JVM engine to treat this class as a REST service.

We are now ready to test our REST service. To do so, right click your Java class and select from the context menu "Test Web Service". This should start your JDeveloper's embedded Weblogic Server and it should open an "HTTP Analyzer" to test your REST service.

If you click on the "Send Request" button, your REST service should be invoked and in the right response panel you should get a response listing all countries in JSON format.

If you recall a few steps before, we configured our REST service to be capable of returning a response back in both JSON and XML format. So why is JSON configured as the default response type?

The answer relies on the @Produces annotation in our Java class. The media type definition order is crucial. As we can see in our class, JSON is configured first and XML is configured as the alternative media type.

So how can we instruct a web service client to request a specific media type response? Well using the "Accept" HTTP header definition. So from the "HTTP Analyzer" window, click on the "HTTP Content" tab and in the "Accept" HTTP header property, update its value to just "application/xml".

If you invoke the service now, you should get an "Internal Server Error" exception (HTTP 500). And if you inspect the log window you should get the following stack trace:

MessageBodyWriter not found for media type=application/xml, type=class java.util.ArrayList, genericType=java.util.List<com.antonis.antoniou.rest.bug.entities.Countries

The reason for getting this exception is that because there is insufficient information in the "Countries" EJB class to help the JVM runtime to interpret the result and map it to the appropriate XML elements.

To fix this exception we need to decorate our "Countries" class with two additional annotations to instruct the engine to perform the proper Java to XML mapping. Therefore add the @XmlRootElement annotation just above the @Entity annotation to map the entire class to be the root XML element and just before each get method (getCountryId, getCountryName and getRegionId) add the @XmlElement annotation to map the countryId, countryName and regionId properties to XML elements.

Let's try to run our REST service again (stop the previous instance and run another test). From the "HTTP Analyzer" window, click on the "HTTP Content" tab, update the "Accept" HTTP Header property to "application/xml" and click on the "Send Request" button. You should now get a response back in XML format.

Update the "Accept" HTTP Header property to "application/json" and click on the "Send Request" button. You should get a response back in JSON format.

Download sample application: REST Service Producing JSON & XML Response Bug and Fix in JDeveloper 12.2.1