Building a simple microservice using Spring Boot

In this short post, I will show how to build a simple JPA Microservice using Spring Boot. Spring Boot makes it easy to create stand-alone based applications that you can run and need very little Spring configuration as we will see in this short tutorial.

springboot

For an explanation about microservices, read this article of Martin Fowler.

As I was saying we are going to use Spring Boot. First start of with a simple java maven enabled project in the IDE of your choice. We will first start with the .pom file to get all the Spring dependencies right. I am going to build a simple ReferenceDataService microservice which can deliver some simple reference data such as a list of countries. Let take a look at the pom file:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <artifactId>ReferenceDataService</artifactId>
    <groupId>nl.redrock</groupId>
    <packaging>jar</packaging>
    <name>ReferenceData Microservice</name>
    <description>ReferenceData Service</description>
    <version>1.0</version>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.2.RELEASE</version>
    </parent>
    
	
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Oracle JDBC driver -->
        <dependency>
            <groupId>com.oracle</groupId>
            <artifactId>ojdbc7</artifactId>
            <version>7.0</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

As you can see, we the 1.5.2.RELEASE as a basis. We then have 4 dependencies. We need spring-boot-starter-web for libraries to creating the rest service, we need spring-boot-starter-data-jpa for the jpa capability, we need spring-boot-starter-test for testing capabilities and last an ojdbc.jar because the data is located in a Oracle database. I am also adding the spring-boot-maven-plugin to be able to run it from maven using Tomcat.

Let start of with the entry point….the application. This is the starting point of our simple service. It will look like this:

package nl.redrock.referencedataservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ReferenceDataApplication {

    public static void main(String[] args) {
        SpringApplication.run(ReferenceDataApplication.class, args);
    }
}

As you can see, it is very simple. Use the @SpringBootApplication annotation to tag it as a Spring Boot application and that is it. Next we want a class which can retrieve data from database. Spring has a bunch helpful classes and templates for you to help with this. I already have a pre-filled oracle database running with 1 table called country. It has 3 columns….ID, CODE and NAME.

database

So as a first step we will create a Country class which maps to the table.

package nl.redrock.referencedataservice.data;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Country {
    
    @Id
    private int id;
    private String code;
    private String name;

    /**
     * @return the id
     */
    public int getId() {
        return id;
    }

    /**
     * @param id the id to set
     */
    public void setId(int id) {
        this.id = id;
    }

    /**
     * @return the code
     */
    public String getCode() {
        return code;
    }

    /**
     * @param code the code to set
     */
    public void setCode(String code) {
        this.code = code;
    }

    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * @param name the name to set
     */
    public void setName(String name) {
        this.name = name;
    }
    
    @Override
    public String toString() {
        return String.format("Country[id=%d, code='%s', name='%s']",
                id, code, name);
    }
}

As you can see this is also a very simple POJO with the 3 attributes mapping to the 3 columns with getter and setters. The annotation which does al the magic here is @Entity. This tells spring that it can be used for Object Relational Mapping. Next we we will create a class which will fetch the data.

package nl.redrock.referencedataservice.repository;

import nl.redrock.referencedataservice.data.Country;
import org.springframework.data.repository.CrudRepository;

public interface CountryRepository extends CrudRepository<Country, Long> {

    Country findById(int id);
}

And again….not much coding here. Just a simple interface which extends Spring’s CRUDRepository. We define just 1 extra interface for retrieving a country by its id. And basically that is it. We just have 1 thing left to do, and that is telling Spring which database to connect to. This is easily done by adding an application.properties to you classpath with all the settings in so it is automatically picked up by Spring.

#port to run apache on
server.port=8888

# Oracle settings
spring.datasource.url=jdbc:oracle:thin:@private.eu-west-1.compute.amazonaws.com:1521:xe
spring.datasource.username=SECRET
spring.datasource.password=SECRET
spring.datasource.driver-class-oracle.jdbc.driver.OracleDriver

#set sql level to debug to see all the sql statements
logging.level.org.hibernate.SQL=debug
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n

The server.port is a setting which you can use to adjust the port tomcat runs on. Next up are the oracle database connection settings. And last of all some logging tweaking. A last thing to do is to make a unit test to see if it al works.

package nl.redrock.referencedataservice.repository;

import junit.framework.TestCase;
import nl.redrock.referencedataservice.data.Country;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.AutoConfigureTestDatabase.Replace;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@DataJpaTest
@AutoConfigureTestDatabase(replace=Replace.NONE)
public class CountryRepositoryTest extends TestCase {
    
    @Autowired
    CountryRepository countryRepository;
    
    @Test
    public void testCountryRepository(){
        Country c = this.countryRepository.findById(1);
        assertTrue(c != null);
        assertTrue(c.getCode().equals("ac"));
        assertTrue(c.getName().equals("Ascension Island"));
    }
}

The things to look for here are the @DataJpaTest annotation which tells Spring it is a JPA test. The @AutoConfigureTestDatabase(replace=Replace.NONE) annotation tells Spring to not replace the application default DataSource.

Run the test:

UT

As you can see, we can fetch data from the database with minimal coding.

Now for the service part. Spring also has easy ways to accommodate this using the @RestController annotation.

package nl.redrock.referencedataservice.controller;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import nl.redrock.referencedataservice.data.Country;
import nl.redrock.referencedataservice.repository.CountryRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/referencedataservice/countries")
public class ReferenceDataController {
    
    private final static Logger LOGGER = Logger.getLogger(ReferenceDataController.class.getName());
    
    @Autowired
    CountryRepository countryRepository;


    @RequestMapping("/{id}")
    public Country getCountry(@PathVariable int id) {
        Country result;
        LOGGER.log(Level.INFO, "Getting country with id " + id);
        result = countryRepository.findById(id);
        return result;
    }

    @RequestMapping(method = RequestMethod.GET)
    List<Country> getCountries() {
        List<Country> result;
        LOGGER.log(Level.INFO, "Getting all countries");
        result = new ArrayList();
        Iterable<Country> countryList = countryRepository.findAll();
        for (Country country : countryList) {
            result.add(country);
        }
        return result;
    }
}

As you can see we implement 2 operations. 1 to get all the countries and 1 to get a specific country by its id. We use @Autowired to inject the countryRepository. And now for the proof of the pudding. Run mvn clean spring-boot:run and watch maven spin up a Tomcat instance with the referencedataservice application deployed on it. Open up the browser and call:

http://localhost:8888/referencedataservice/countries

countriesResult

Now call http://localhost:8888/referencedataservice/countries/160 to get a specific country

countryResult

As you can see Spring makes it very easy to create rest services with minimal coding. If you want to look into some more advanced microservice features Spring has to offer, have a look here and here to see how you can use microservices in conjunction with Netflixs Eureka server.

SOA Suite 12C: Generating a JSON Web Token (JWT) in OSB

“JSON Web Token (JWT) is a JSON-based open standard (RFC 7519) for creating access tokens that assert some number of claims. For example, a server could generate a token that has the claim “logged in as admin” and provide that to a client. The client could then use that token to prove that it is logged in as admin. The tokens are signed by the server’s key, so the client is able to verify that the token is legitimate. The tokens are designed to be compact, URL-safe and usable especially in web browser single sign-on (SSO) context. JWT claims can be typically used to pass identity of authenticated users between an identity provider and a service provider, or any other type of claims as required by business processes. The tokens can also be authenticated and encrypted.” Wikipedia

jwt

I guess the above text says it all. I won’t be going into all the JWT details as you can read most of it online on JWT.io. For my current customer I had to interface with a SaaS product which used JWT as authentication measure. There are quite some libraries for Java which you can use to generate tokens. To mention a few:

  • com.auth0.java-jwt
  • org.bitbucket.b_c.jose4j
  • com.nimbusdsnimbus.jose-jwt
  • io.jsonwebtoken.jjwt

Easy as I thought, I grabbed the most obvious one I could find and created a simple class which could create a token for me. Sounded fairly easily but the used jar also had it’s dependencies which of course had to be available in Weblogic also for it to work. This is where the problem started as the dependencies seem to cause some class loading issues. I tried another JWT implementation but this also seem to cause some issues. After some googling I found that Oracle also had JWT support looking at the page. The only thing I really couldn’t find very quickly was which jars I needed and where they where….

After some poking around in my Oracle_Home I found the right jars though. The ones you need to create a token are:

  • osdt_cert.jar
  • osdt_core.jar
  • osdt_restsec.jar
  • jackson-core-asl-1.1.1.jar
  • jackson-mapper-asl-1.1.1.jar

The first 3 are located in your OracleHome\oracle_common\modules\oracle.osdt_12.1.3 folder. The 2 jackson ones you can just grab of the internet
These jars contain all the classes you need to create a token and verify it in your Java development environment. The first three are already on your Weblogic classpath. The two Jackson also seem to be somewhere on the server although the documentation makes you think otherwise but I didn’t need to put the 2 Jackson libraries somewhere on the server to make it work.

To create a token you can just use the following code for example:

package nl.redrock.jwt;

import oracle.security.restsec.jwt.*;

public class JWTGenerator {
    
    
    public static String generateJWT(String aCode, String aAmount, String aKey) throws Exception {
        
        String result = null;
        
        JwtToken jwtToken = new JwtToken();
        //Fill in all the parameters- algorithm, issuer, expiry time, other claims etc
        jwtToken.setAlgorithm(JwtToken.SIGN_ALGORITHM.HS512.toString());
        jwtToken.setType(JwtToken.JWT);
        jwtToken.setClaimParameter("Amount", aAmount);
        jwtToken.setClaimParameter("Code", aCode);
        // Get the private key and sign the token with a secret key or a private key
        result = jwtToken.signAndSerialize(aKey.getBytes());
        return result;
    }
}

To call the generateJWT class, just create a custom xquery lib file…in my case custom-redrock-xquery.xml which looks like this:

<?xml version="1.0" encoding="UTF-8" ?>
<xpf:xpathFunctions xmlns:xpf="http://www.bea.com/wli/sb/xpath/config">
	<xpf:category id="RedRock Custom Functions">
		<xpf:function>
			<xpf:name>generateJWT</xpf:name>
			<xpf:comment>Generate a JSON Web Token based on inputs</xpf:comment>
			<xpf:namespaceURI>http://www.redrock.nl/soa/xpath</xpf:namespaceURI>
			<xpf:className>nl.redrock.jwt.JWTGenerator</xpf:className>
			<xpf:method>java.lang.String generateJWT(java.lang.String, java.lang.String, java.lang.String)</xpf:method>
			<xpf:isDeterministic>false</xpf:isDeterministic>
			<xpf:scope>Pipeline</xpf:scope>
			<xpf:scope>SplitJoin</xpf:scope>
		</xpf:function>
	</xpf:category>
</xpf:xpathFunctions>

Stick this file under OracleHome\osb\config\xpath-functions along with the jar-file which contains your utility class and dont’t forget the osdt_restsec.jar as it is a dependency which seems to be needed at deploytime. Then start JDev up and in XQuery Expression builder popup you should now see the custom xquery.

xqueryexpressionbuilder

Now just deploy you project to the servicebus and run a test. If you enable execution tracing you will see that the assign works and we get a token.

token

Next select the token and go to JWT.io and check if it verifies:

jwtcheck

A first glance at Mule’s API capabilities

Since 2006, Mulesoft is offering middleware and messaging. Back then, building integrations was still heavily XML file based, with a set of Eclipse based plugins. This has changed though! With their Anypoint Studio, an Eclipse-based graphical development environment for designing, testing and running Mule flows, they really upped their game. Together with their new IPaaS platform CloudHub and their API capabilities, Mulesoft is looked at as a big player in IPaaS and API arena as shown in a previous article here where both Gartner and Ovum rate them as leaders. To add to that, Mulesoft was placed in the Forbes Cloud top 100 at number 20.

mulesoft

As I was quite curious how the new studio compared to my daily integration work with JDeveloper, I downloaded it and gave it a swing with a simple integration. You can download Anypoint Studio right here.

I started of by creating a simple mule project. File > New > Mule Project and clicking finish. As you can see, you can also use Maven but I will leave this unchecked for now.

MuleProject

After clicking finish you will see that it generates a project structure on the left side:

MuleProjectExplorer

In the middle is the canvas on which you can drag and drop items from the palette which is on the right. Straight away you can see there are quite a few connector which come out-of-the-box.

MuleProjectConnectors

I will start of with a HTTP connector. You can search in palette by typing HTTP. Now just drag the component onto the canvas. When you select the component, you can see the properties at the bottom. I will just keep the HTTP Display Name but I will set the Path to /simplemuleservice. Then I will need to generate a listener configuration by clicking the + sign on the right. I will accept all the default values which are 0.0.0.0 at port 8081. Next I am going to add a simple response. Look for Set Payload in the palette and drag it in the box next to the HTTP connector. Now select it and input a value. Mine is Hello…this is a simple Mule service.

setpayload

Next lets add some Logging. Add the Logger component and add it to the canvas. In the Message property of the Logger we can state what we want to log. The settings for the logging are defined in the log4j2.xml under resources. You can also use the Mule expression language here to access all sorts of info. I will just log all of the parameters send with the request by adding the next message: My simple mule service called with parameter #[message.inboundProperties.'http.query.params']

logger

Now save the whole project. Lets see if it also runs. Just right click the application a choose > Run as > Mule application.

You can see the application is running.

running

Now open your browser and type in server and port you defined. In my case http://localhost:8081/simplemuleservice. As I also added the parameters to the Logger step, I will also add some of those like this: http://localhost:8081/simplemuleservice?caller=Hugo&message=Hi

As you will see the browser will respond with the output we defined.

browser

And the logging shows:
loggerOutput

As you can see, creating a flow is much easier then before. Underneath it is still al XML but the visual wrapper around it makes it easier to work with in my opinion. This was actually a very simple flow. The next step is to do something which is a bit more work but more like an actual usecase.

Lets say we have a SOAP service running on-premise. We want to expose that service as an API to the outside world. So basically 2 things:

  • Design the API first
  • Convert REST to SOAP and call the webservice
  • Convert the SOAP response back to a JSON result and return it

I want to make an API for a webservice which I have used before…..the ConversionRateService. It has 2 input values. FromCurrency and ToCurrency. The result is ConversionRate result. So let’s start with creating a simple RAML file. Mine looks like this:

#%RAML 1.0
title: Conversionrate API
version: v1.0
baseUri: http://conversionrate/api
mediaType: application/json
documentation:
  - title: Introduction
    content: |
      API to lookup currency conversion rates
/convert:
  get:
    responses:
      200:
        body:
          example: |
            {
                "conversionrate" : "1.2345",
                
            }

Now that we have our RAML file, start a new project, in my case simplemule2. Don’t forget to tick the Add APIkit components box below and select the RAML file we just created.

newProject

When you click finish, Anypoint Studio will generate skeletal backend flows, based on the RAML file. The next step is to delete the Set Payload in the get:/convert:conversionrate-config. This is the flow in which we will call our webservice. Drag the Web Service Consumer component onto the canvas. Then down below we can create a Connector Configuration.

webserviceconsumer. I used the WSDL from an old project here.

Now that I have the call to the webservice, I have to map the rest call to soap. Drag a Transform Message before the Web Service Consumer component. If you look at the properties below, you can see on the left side the Input, and on the right side the output. As the input parameters will be incoming as http query parameters, we can just type in the mapper file on the right, how we want to map them.

mapRequest

Next we want to transform the result from SOAP to a JSON response so drag another Transform Message but this time place it after the Web Service Consumer component. Again look at the properties below. On the left side you can the the data model of the webservice response. The right side Output shows unknown. As I just want to map the response, you can edit the result on the right side like shown below:

mapResponse

As you can see, we will return a simple JSON response in which we map the conversionrate field to the webservice response field ConversionRateResult. Save it and we are ready to test the application. To make it easy for myself, I have created the conversionrate webservice using SoapUI by importing the WSDL and creating a Mock service. It is running on http://localhost:8005/mockConversionRateService as defined in the Web Service Consumer component.

Now right click the application and choose Run as–> Mule application. As you can see it will also start the APIkit console automatically. It shows the description of the API and an interface to make calls. I will just use a good old browser call like this: http://localhost:8081/api/convert?FromCurrency=EUR&ToCurrency=USD which result in

mockResponse

As you can see, it hits the SoapUI mock which returns a SOAP response which is processed by Mule which returns a JSON response.

restResponse

I was surprised how easy it was to create an API design first. The UI works nice and easy and everything is deployed nice and fast on the integrated Mule server. I have just scratched the surface here of Mule’s capabilities but I am liking what I am seeing.

Consuming a service in Oracle Service Bus 12C using the REST adapter

In a previous post I have shown how to create a REST service in 12C. That was easy. But how do we consume a REST service? In this next bit I will show how to do that. The REST service we are going to use is Google’s Geocoding API. You can use this API to input address data and retrieve geo data in both JSON or XML. For example:

GoogleGeo

To consume this service in 11G we had to do quite some work….see here. Lets see if it has become more easy now in 12C.

First we are going to create the service how we are going to expose our service. We have the XSD and WSDL from the previous project so we are just going to reuse that. Create a new ServiceBus project GeoService and drag a new Pipeline onto your canvas. Name your pipeline GeoServicePipeline and click next. Next define its interface by selecting the WSDL using the icon with the green arrow. As you can see my WSDL is located in a folder called wsdl. Also check the box below ‘Expose as a Proxy Service’ and click Finish.

WSDL

As you can see we have now a simple proxy service doing nothing.

Skeleton

We now have to hook it up to the Google backend. As seen in the previous post, a WADL is a description of how to use a REST service, comparable to a WSDL for SOAP services. So basically I am looking for a WADL for the Geocode API. After some looking around I found a SoapUI project containing a few Google API services with their created WADL’s in there. So basically I grabbed the WADL from there and I did some tweaking and tuning as I saw that when creating the REST adapter in JDeveloper, it was picky with some settings. The WADL I created looks as followed:

<application xmlns="http://wadl.dev.java.net/2009/02"
    xmlns:soa="http://www.oracle.com/soa/rest" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:sch="http://www.google.com/geocode/service/schema">
   <doc xml:lang="en" title="Geocoding API"/>
   <grammars>
      <xsd:schema targetNamespace="http://www.google.com/geocode/service/imports" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
            <xsd:import schemaLocation="GoogleGeocode.xsd" namespace="http://www.google.com/geocode/service/schema"/>
        </xsd:schema>
   </grammars>
   <resources base="http://maps.googleapis.com">
      <resource path="maps/api/geocode/xml" id="geocode">
         <doc xml:lang="en" title="geocode"/>
         <param name="address" style="query" soa:expression="$msg.parameters/sch:address" default="" type="xsd:string"/>
         <param name="sensor" style="query" soa:expression="$msg.parameters/sch:sensor" default="false" type="xsd:string"/>
         <param name="language" style="query" soa:expression="$msg.parameters/sch:language" default="EN" type="xsd:string"/>
         <method name="GET" id="GET">
            <doc xml:lang="en" title="GET"/>
            <request/>
            <response status="200">
               <representation mediaType="application/xml" element="sch:GeocodeResponse" xmlns:sch="http://www.google.com/geocode/service/schema"/>
            </response>
         </method>
      </resource>
   </resources>
</application>

with matching XSD:

<?xml version = '1.0' encoding = 'UTF-8'?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
            xmlns:nxsd="http://xmlns.oracle.com/pcbpel/nxsd" nxsd:encoding="US-ASCII"
            xmlns:tns="http://www.google.com/geocode/service/schema"
            targetNamespace="http://www.google.com/geocode/service/schema">
  <xsd:element name="address" type="xsd:string"/>
  <xsd:element name="language" type="xsd:string"/>
  <xsd:element name="sensor" type="xsd:string"/>
  <xsd:element name="GeocodeResponse">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="status" type="xsd:string"/>
        <xsd:element name="result">
          <xsd:complexType>
            <xsd:sequence>
              <xsd:element name="type" type="xsd:string"/>
              <xsd:element name="formatted_address" type="xsd:string"/>
              <xsd:element name="address_component" maxOccurs="unbounded">
                <xsd:complexType>
                  <xsd:sequence>
                    <xsd:element name="long_name" type="xsd:string"/>
                    <xsd:element name="short_name" type="xsd:string"/>
                    <xsd:element name="type" maxOccurs="unbounded" type="xsd:string"/>
                  </xsd:sequence>
                </xsd:complexType>
              </xsd:element>
              <xsd:element name="geometry">
                <xsd:complexType>
                  <xsd:sequence>
                    <xsd:element name="location">
                      <xsd:complexType>
                        <xsd:sequence>
                          <xsd:element name="lat" type="xsd:double"/>
                          <xsd:element name="lng" type="xsd:double"/>
                        </xsd:sequence>
                      </xsd:complexType>
                    </xsd:element>
                    <xsd:element name="location_type" type="xsd:string"/>
                    <xsd:element name="viewport">
                      <xsd:complexType>
                        <xsd:sequence>
                          <xsd:element name="southwest">
                            <xsd:complexType>
                              <xsd:sequence>
                                <xsd:element name="lat" type="xsd:double"/>
                                <xsd:element name="lng" type="xsd:double"/>
                              </xsd:sequence>
                            </xsd:complexType>
                          </xsd:element>
                          <xsd:element name="northeast">
                            <xsd:complexType>
                              <xsd:sequence>
                                <xsd:element name="lat" type="xsd:double"/>
                                <xsd:element name="lng" type="xsd:double"/>
                              </xsd:sequence>
                            </xsd:complexType>
                          </xsd:element>
                        </xsd:sequence>
                      </xsd:complexType>
                    </xsd:element>
                  </xsd:sequence>
                </xsd:complexType>
              </xsd:element>
            </xsd:sequence>
          </xsd:complexType>
        </xsd:element>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>
</xsd:schema>

Stick these 2 files in a folder thirdparty under you project. Now open your composite and drag the REST Adapter component to the External Service swimlane.

RestAdapter

Input the name and then click the green + at the bottom and select ‘Add operations based on WADL service’. Now select the WADL in the thirdparty folder and click OK. As you can see, the resource path and operation bindings are filled in. Also when you select the GET binding and click the pencil. You can see that both the request and response parameters are set.

RequestResponse

Now click on OK and JDeveloper will generate a business service, a WADL and a WSDL for you. The WADL and WSDL are under Resources but the business service is in the root. To keep it clean I move the business service to the business folder. It might disappear from your swim lane but you can just drag it onto it again from your project.

Composite

Now lets hook at all together. Connect the Pipeline with the REST adapter and open the pipeline. Add a Replace action in the Request route pipeline with the following xpath.

XpathInput

Don’t forget the namespaces. Now also input a Replace action in the Response route pipeline with the following xpath.

OutputXpath

In the Route set the Operation to GET.

Route

Save the whole project and deploy it. Open your EM and lets see if the service works.

Test

As you can see, the longitude and latitude are returned in the correct manner.

So, basically the conclusion is that the new 12C REST Adapter really makes your life easier when consuming a REST service. The only thing you might struggle with a bit is to get the WADL correct but once you get the hang if it, it is not too bad.

Creating a REST service in Oracle Service Bus 12C

In this first REST post I will demonstrate how to make easily expose a REST service in the Service Bus 12C. I will not explain REST as quite some people have already written tons of stuff about this….Google is your friend :) . Exposing a service in a REST way using the new 12C release is quite simple. Lets try and expose the ConversionRateService we previously build as a REST service.

Right click the Pipeline you want to expose and select Expose as REST.

ExposeAsREST

A popup opens where you can define the name of the service and it’s resource path. In our case I will name it ConversionRateRestService and will set its resource path to /json. You can do this by pressing the little pencil on the right.

ResourcePath

The only thing we now have to do is set the operational bindings. Click the GetConversionRate operation below and click the pencil. Another popup opens where you can set the HTTP verb which will be GET in our case. Down below you can see the request parameters and the expression of how to use them.

Binding

Now click the Response tab to define in which form we want our data returned. De-select the XML box and select the JSON box as we want our service to return JSON instead of XML.

JSON

Then press OK twice and voila. You have exposed your service!

If you want you can also expose another REST service which will return XML. Follow the previous steps but you have to remember that you cannot have two proxy services with the same Endpoint URI. So what I did, I created 2 proxy services with a different URI…..for example /financial/conversionraterestservice/1.0/xml for the xml version and /financial/conversionraterestservice/1.0/json for the JSON version. When you do that, you can leave the Resource Path of the REST binding on /

Binding

This way you can easily expose your functionality in three ways: SOAP

ExposeAsSOAP

or REST with JSON

RESTWithJSON

or REST with XML

RESTWithXML

In the next post I will show how to consume a REST service using the 12C Service Bus

Converting JSON to XML in the OSB when consuming a REST service.

In my previous post I showed you how you could consume the Google Geo service using the OSB. In that example we used XML as the return format. It was also possible to return JSON. JSON stands for JavaScript Object Notation and is smaller then XML and faster en easier to parse. The JSON text format is syntactically identical to the code for creating JavaScript objects. That is why it is used more often now by frontend frameworks such as Apache Isis for example.

In this post I will show you how you can parse the JSON returned from Google using the OSB. To convert XML to JSON and JSON to XML, you can create a helper class in Java which can do this for you. Make the convenience methods public and static so you can use them in a Java Callout in the OSB. My class looks like this:

package nl.redrock.common;

import net.sf.json.JSON;
import net.sf.json.JSONObject;
import net.sf.json.JSONSerializer;
import net.sf.json.xml.XMLSerializer;

/**
 * This class hold a couple of static methods which can be used to convert xml to json and json into xml.
 * @author Hugo Hendriks
 *
 */
public class XMLJSONConverter {

	/**
	 * Converts a Json String to a XML string
	 * @param aRootName the name of the root element in the xml
	 * @param aJson the json string
	 * @return null or a string which holds the xml representation of the json string
	 * @throws Exception
	 */
	public static String convertJSON2XML(String aRootName, String aJson) throws Exception {
		String result = null;

        XMLSerializer xmlSerializer = new XMLSerializer();
        xmlSerializer.setRootName(aRootName);
        JSON json = JSONSerializer.toJSON( aJson );
        result = xmlSerializer.write( json );
        return result;
	}

	/**
	 * Convert a XML string to a json string
	 * @param aXml the XML string
	 * @return null or a string which holds the json representation of the xml string
	 * @throws Exception
	 */
	public static String convertXML2JSON(String aXml) throws Exception {
		String result = null;

		XMLSerializer xmlSerializer = new XMLSerializer();
		xmlSerializer.setTypeHintsEnabled(false);
		JSONObject json = (JSONObject) xmlSerializer.read(aXml);
		result = json.toString();
        return result;
	}

}

I use maven as my build tool and my pom file looks like this:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>nl.redrock.common</groupId>
	<artifactId>XmlJsonConverter</artifactId>
	<version>1.0</version>
	<name>XmlJsonConverter</name>
	<description>This library can be used to convert XML into JSON and back again</description>

	<dependencies>
		<dependency>
			<groupId>net.sf.json-lib</groupId>
			<artifactId>json-lib</artifactId>
			<version>2.4</version>
			<type>jar</type>
			<classifier>jdk15</classifier>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-io</artifactId>
			<version>1.3.2</version>
			<type>jar</type>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>xom</groupId>
			<artifactId>xom</artifactId>
			<version>1.2.5</version>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.10</version>
			<type>jar</type>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-dependency-plugin</artifactId>
				<version>2.5.1</version>
				<executions>
					<execution>
						<id>copy-dependencies</id>
						<phase>package</phase>
						<goals>
							<goal>copy-dependencies</goal>
						</goals>
						<configuration>
							<outputDirectory>${project.build.directory}/libs</outputDirectory>
							<overWriteReleases>true</overWriteReleases>
							<overWriteSnapshots>true</overWriteSnapshots>
							<overWriteIfNewer>true</overWriteIfNewer>
						</configuration>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</project>

You can see I am using the Maven dependency plugin to create a directory which holds all the dependencies jars. This is done because I need a few of these libraries on the weblogic server. In the MY_DOMAIN/lib directory to be precise.

This is the case for:

  • json-lib-2.4-jdk15.jar
  • ezmorph-1.0.6.jar
  • xom-1.2.5.jar

You can get these from the libs directory created by maven when you run the mvn -clean -package target. The other libraries are already available in Weblogic.

After this, you can add your XMLJSONConverter library to your project.

Then you can make a java callout in which you can convert the received json into a xml string.

After that, you can parse the string to real xml by making use of the fn-bea:inlinedXML() function.

So now you know how you can convert JSON to XML and vice versa.

Example was made in 11G PS4

Consuming Google Geo REST service using the OSB

In this article I will explain how you can make use of the Google Geo Service API using the OSB. Check out this page to see what we can do with this API. Basically it makes it possible to enter address details and Google comes up with the geographical details including longitude and latitude if Google can find it. The result can either be returned as JSON or as XML. In this example we are going build a webservice in the OSB which will call Google and transform the returned XML into a nice response.

So lets start with making a simple WSDL which is going to expose the Google API. Mine looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions name="GeoService" targetNamespace="http://www.redrock.nl/geo/service" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://www.redrock.nl/geo/service" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:geo="http://www.redrock.nl/geo/service/schema">
	<wsdl:types>
		<xsd:schema targetNamespace="http://www.redrock.nl/imports" elementFormDefault="qualified">
			<xsd:import schemaLocation="../Schemas/GeoService.xsd" namespace="http://www.redrock.nl/geo/service/schema" />
		</xsd:schema>
	</wsdl:types>
	<wsdl:message name="GetGeocodeRequest">
		<wsdl:part name="parameters" element="geo:GetGeocodeRequest">
		</wsdl:part>
	</wsdl:message>
	<wsdl:message name="GetGeocodeResponse">
		<wsdl:part name="parameters" element="geo:GetGeocodeResponse">
		</wsdl:part>
	</wsdl:message>
	<wsdl:portType name="GeoService">
		<wsdl:operation name="GetGeocode">
			<wsdl:input message="tns:GetGeocodeRequest">
			</wsdl:input>
			<wsdl:output message="tns:GetGeocodeResponse">
			</wsdl:output>
		</wsdl:operation>
	</wsdl:portType>
	<wsdl:binding name="GeoService" type="tns:GeoService">
		<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
		<wsdl:operation name="GetGeocode">
			<soap:operation soapAction="http://www.redrock.nl/geo/service/getgeocode"/>
			<wsdl:input>
				<soap:body use="literal"/>
			</wsdl:input>
			<wsdl:output>
				<soap:body use="literal"/>
			</wsdl:output>
		</wsdl:operation>
	</wsdl:binding>
	<wsdl:service name="GeoService">
		<wsdl:port name="GeoServicePort" binding="tns:GeoService">
			<soap:address location="http://www.redrock.nl/geo/service"/>
		</wsdl:port>
	</wsdl:service>
</wsdl:definitions>

With the data defined in a seperate file GeoService.xsd.

<?xml version="1.0" encoding="UTF-8"?>
<!-- edited with XMLSpy v2011 rel. 2 sp1 (http://www.altova.com) by Hugo Hendriks -->
<xsd:schema xmlns:tns="http://www.redrock.nl/geo/service/schema" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.redrock.nl/geo/service/schema" elementFormDefault="qualified">
	<xsd:element name="GetGeocodeRequest">
		<xsd:complexType>
			<xsd:sequence>
				<xsd:element name="Street" minOccurs="1" maxOccurs="1" type="xsd:string"/>
				<xsd:element name="Number" minOccurs="1" maxOccurs="1" type="xsd:integer"/>
				<xsd:element name="City" minOccurs="1" maxOccurs="1" type="xsd:string"/>
			</xsd:sequence>
		</xsd:complexType>
	</xsd:element>
	<xsd:element name="GetGeocodeResponse">
		<xsd:complexType>
			<xsd:choice>
				<xsd:element ref="tns:Messages"/>
				<xsd:sequence>
					<xsd:element name="Longitude" type="xsd:string"/>
					<xsd:element name="Latitude" type="xsd:string"/>
				</xsd:sequence>
			</xsd:choice>
		</xsd:complexType>
	</xsd:element>
	<xsd:element name="Messages">
		<xsd:complexType>
			<xsd:sequence>
				<xsd:element name="Message">
					<xsd:complexType>
						<xsd:sequence>
							<xsd:element name="Code">
								<xsd:annotation>
									<xsd:documentation>The code</xsd:documentation>
								</xsd:annotation>
							</xsd:element>
							<xsd:element name="Description">
								<xsd:annotation>
									<xsd:documentation>The description</xsd:documentation>
								</xsd:annotation>
							</xsd:element>
						</xsd:sequence>
					</xsd:complexType>
				</xsd:element>
			</xsd:sequence>
		</xsd:complexType>
	</xsd:element>
</xsd:schema>

First we are going to create a business service which will call Google. Create it as a messaging service:

Set the Request Message Type to none and the Response Message Type to XML.

And finally set the Endpoint URI to http://maps.googleapis.com/maps/api/geocode/xml

Next we are going to create a proxy service which uses the created WSDL.

After this we do the usuall stuff we want to do in our flow like a bit of logging, validation and errorhandling. As a last step insert a Route and a Routing and select the BusinessService we created.

But now for the good part. We need to make a HTTP GET request to Google with a certain set of http-parameters. You can test this in your own browser by using the following example URI: http://maps.googleapis.com/maps/api/geocode/xml?address=koningsplein+1+amsterdam&sensor=false&language=nl. Try and input your own address in there to see if Google can find it for you. In this case the http-parameters are:¬†address=koningsplein+1+amsterdam. The sensor=false means we are not using a measuring device and the language parameter speaks for itself. Oke…..how do we make a HTTP GET request to Google using these parameters. You can accomplish this by adding an Insert action to you Route with the following settings:

This insert chances the HTTP request from a PUT to a GET. The next step is to set the http-parameters. This is done like this:

You can see we insert another piece of xml into the outbound variable. We are using an XQuery to create this piece of xml. Mine looks like this:

(:: pragma bea:global-element-parameter parameter="$GetGeocodeRequest" element="geo:GetGeocodeRequest" location="../Schemas/GeoService.xsd" ::)
(:: pragma bea:global-element-return element="http:query-string" location="../Schemas/HttpTransport.xsd" ::)

declare namespace http = "http://www.bea.com/wli/sb/transports/http";
declare namespace geo = "http://www.redrock.nl/geo/service/schema";
declare namespace xf  = "http://www.redrock.nl/transformation/SoapToHttpGet/";

declare function xf:SoapToHttpGet($GetGeocodeRequest as element(geo:GetGeocodeRequest))
    as element(http:query-string) {
        <http:query-string>{ concat("address=",$GetGeocodeRequest/geo:Street , "&#043;" ,$GetGeocodeRequest/geo:Number, "&#043;",
                           					 $GetGeocodeRequest/geo:City, "&#38;sensor=false&#38;language=nl") }
        </http:query-string>
};

declare variable $GetGeocodeRequest as element(geo:GetGeocodeRequest) external;

xf:SoapToHttpGet($GetGeocodeRequest)

You can see we create a query-string element using the request we receive from the user. The HttpTransport.xsd is needed for this which also has some references to their xsd’s (EnvValues.xsd, MessageContext.xsd and TransportCommon.xsd) so make sure to put these in your Schemas directory. So in the end, my project looks like this:

When we make the call to Google, we receive XML back which we want to transform into a response previously defined. First we check if we receive an answer at all or multiple answers.

Next we transform the response into our pre-defined response using a replace of the body.

<sch:GetGeocodeResponse>
	<sch:Longitude>{$body/GeocodeResponse/result/geometry/location/lng/text()}</sch:Longitude>
	<sch:Latitude>{$body/GeocodeResponse/result/geometry/location/lat/text()}<sch:Latitude>
</sch:GetGeocodeResponse>

Now lets deploy and test the service.Lets use the previously used parameters for the call in the browser which where Koningsplein 1 in Amsterdam. You test in the webconsole should look something like this:

As you can see we receive the latitude and logitude for the address. As we look deeper into the Route we can see how the $outbound is transformed:

So now you know how you can consume a REST service using the OSB.

btw: You can make a maximum of 2500 calls per day using this service. If you want to make more calls, you have to get a business account.

2016-07-16: I added the code by request here