Friday, 10 March 2017

Secure RESTFul API using OAuth2 : Spring

This blog is the extension of my previous blog in which we have explained how to develop RESTFul APIs using Spring and Hibernate.

This time is to implement OAuth 2 in REST APIs. Security is the primary concern for all organization.

OAuth 2 is one of the most popular protocol for the security implementation. This is totally based on the token mechanism. However there lot's of security mechanism that anybody can use to secure APIs or any web application.

In this blog, we are gonna to implement OAuth only. Let's have a quick look on what OAuth 2 says.

The OAuth2 authorization framework enables a third-party application to obtain limited access to an HTTP service, either on behalf of a resource owner by orchestrating an approval interaction between the resource owner and the HTTP service, or by allowing the third-party application to obtain access on its own behalf.

This is as per the documentation of OAuth2

Most of the big enterprises like Google, Facebook, Twitter are using OAuth2 security.

Let's have quick look on the four key concept of OAuth:


1) OAuth 2 Roles: There are four roles defined in OAuth:

  • resource owner: It could be an entity capable of granting access to the protected resource. When the entity owner is a person, it is referred to as an end-user.
  • resource server: The resource server is capable to host the secure resources, accepting request and responding to the protected request resource using the access token.
  • client: This is an application making request of the secured resources on behalf of resources owner and with its authorization. It could be a mobile client asking to access your Facebook feeds,  a web site providing an alternative login using gmail account.
  • authorization server: The server issuing access tokens to the client after successfully authenticating the resource owner and obtaining authorization.

2. OAuth2 Authorization Grant types

An authorization grant is a credential representing the resource owner’s authorization (to access its protected resources) used by the client to obtain an access token. The specification defines four grant types:

  • authorization code
  • implicit
  • resource owner password credentials
  • client credentials

We will be using resource owner password credentials grant type.

3. OAuth2 Tokens

Tokens are random strings, generated by the authorization server and are issued when the client requests them.

  • Access Token: Sent with each request, usually valid for a very limited amount of  time
  • Refresh Token: Mainly used to get a new access token, not sent with each request, usually lives longer than access token.


4. OAuth2 Access Token Scope

Client can ask for the resource with specific access rights using scope [want to access feeds & photos of this users facebook account], and authorization server in turn return scope showing what access rights were actually granted to the client [Resource owner only allowed feeds access, no photos e.g.].

Let's get started with the actual implementation:

1) Resource Server: Resource servers are capable to host the resources(for ex REST APIs) the client is interested in. Resources are located on /employees/. @EnableResourceServer annotation, applied on OAuth2 Resource Servers, enables a Spring Security filter that authenticates requests using an incoming OAuth2 token.

package com.test.security;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler;

@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
 
    private static final String RESOURCE_ID = "rest_api";
     
    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        resources.resourceId(RESOURCE_ID).stateless(false);
    }
 
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.
        anonymous().disable()
        .requestMatchers().antMatchers("/employees/**")
        .and().authorizeRequests()
        .antMatchers("/employees/**").access("hasRole('ADMIN')")
        .and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
    }
 
}




2. Authorization Server

Authorization server is the one responsible for verifying credentials and if credentials are valid, it generated the tokens[refresh-token as well as access-token]. It also contains information about registered clients and possible access scopes and grant types. The token store is used to store the token. We will be using an in-memory token store.

package com.test.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.approval.UserApprovalHandler;
import org.springframework.security.oauth2.provider.token.TokenStore;
 
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
 
    private static String REALM="REALM";
     
    @Autowired
    private TokenStore tokenStore;
 
    @Autowired
    private UserApprovalHandler userApprovalHandler;
 
    @Autowired
    @Qualifier("authenticationManagerBean")
    private AuthenticationManager authenticationManager;
 
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
 
        clients.inMemory()
            .withClient("secure-client")
            .authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")
            .authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
            .scopes("read", "write", "trust")
            .secret("password@123")
            .accessTokenValiditySeconds(60).//Access token is only valid for 1 minutes.
            refreshTokenValiditySeconds(300);//Refresh token is only valid for 5 minutes.
    }
 
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(tokenStore).userApprovalHandler(userApprovalHandler)
                .authenticationManager(authenticationManager);
    }
 
    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer.realm(REALM+"/client");
    }
 
}



3. Security Configuration

Endpoint /oauth/token is used to request a token [access or refresh]. Resource owners(ankur and devesh) are configured.

package com.test.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.approval.ApprovalStore;
import org.springframework.security.oauth2.provider.approval.TokenApprovalStore;
import org.springframework.security.oauth2.provider.approval.TokenStoreUserApprovalHandler;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
 
@Configuration
@EnableWebSecurity
public class OAuth2SecurityConfiguration extends WebSecurityConfigurerAdapter {
 
    @Autowired
    private ClientDetailsService clientDetailsService;
     
    @Autowired
    public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
        .withUser("ankur").password("password@123").roles("ADMIN").and()
        .withUser("devesh").password("password@123").roles("USER");
    }
 
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
        .csrf().disable()
        .anonymous().disable()
        .authorizeRequests()
        .antMatchers("/oauth/token").permitAll();
    }
 
    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
 
 
    @Bean
    public TokenStore tokenStore() {
        return new InMemoryTokenStore();
    }
 
    @Bean
    @Autowired
    public TokenStoreUserApprovalHandler userApprovalHandler(TokenStore tokenStore){
        TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
        handler.setTokenStore(tokenStore);
        handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
        handler.setClientDetailsService(clientDetailsService);
        return handler;
    }
     
    @Bean
    @Autowired
    public ApprovalStore approvalStore(TokenStore tokenStore) throws Exception {
        TokenApprovalStore store = new TokenApprovalStore();
        store.setTokenStore(tokenStore);
        return store;
    }
     
}

Additionally, enable Global method security which will activate @PreFilter, @PostFilter, @PreAuthorize @PostAuthorize annotations if we want to use them.

package com.test.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
import org.springframework.security.oauth2.provider.expression.OAuth2MethodSecurityExpressionHandler;
 
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
    @Autowired
    private OAuth2SecurityConfiguration securityConfig;
 
    @Override
    protected MethodSecurityExpressionHandler createExpressionHandler() {
        return new OAuth2MethodSecurityExpressionHandler();
    }
}

Let's see the below sequence, how to make protected resource call with access token

1) Make the HTTP POST request for access and refresh tokens with the below URL. Additionally,  send the client credentials, in the Authorization header.

http://localhost:8081/RestApi/oauth/token?grant_type=password&username=ankur&password=password@123

2) Make the HTTP GET/POST/PUT/DELETE request with the access token. For ex, if you want to make HTTP GET request, below URL would be used:

http://localhost:8081/RestApi/employees/2?access_token=cbbe9860-df48-44aa-b1fa-b8de01ca8916

3) If your access token expires, make the HTTP POST request to get the new access token. Additionally,  send the client credentials, in the Authorization header.

http://localhost:8081/RestApi/oauth/token?grant_type=refresh_token&refresh_token=235b9a77-baea-4ea6-bc15-8b975f8fbf89

Let's hit some request using POSTMAN client:

1) Let's hit the request without access token and see the response:



2) Let's generate the access token:


3) Let's hit the HTTP GET request with the access token in query parameter:


4) Wait for a minute and hit the HTTP GET request again, you will see token expiration message.


5) Generate a new access token with the help of refresh token whose validity is 5 minutes.


6) Hit the HTTP GET request again with the new access token



7) Let's hit refresh token request after 5 minutes and see refresh token is also get expired:





Download source code from here

Friday, 3 March 2017

RESTFul API in Spring MVC : CRUD Operation

REST stands for Representational State Transfer. It’s an is an architectural style which can be used to design web services, that can be consumed from a variety of clients. The core idea is that, rather than using complex mechanisms such as CORBA, RPC or SOAP to connect between machines, simple HTTP is used to make calls among them.

In a REST webservices, resources are being manipulated using a common set of HTTP verbs.

GET : It is used when user sends a Read request
POST : It is used when user sends a Create request
PUT : It is used when user sends a Update request
DELETE : It is used when user sends a Delete request

So, in the example below we will use all the above HTTP verbs.

REST services are basically developed to send the JSON response, because it is very light weight and easy to parse for any third party application compared to XML. REST services are not only to send JSON response, it can send XML as well. It's totally depend on the requirement.

In this example, we are gonna to use java based configuration for Spring and Hibernate, instead of XML based configuration.

We will use Spring 4.2.5 for this example.

After this blog, you should have learned to:

1) How to develop REST websevices in Spring and Hibernate
2) How to use different HTTP verbs
3) How to send response in JSON

To compile this example, you should have the below:

1) Eclipse
2) JDK 1.6+
3) MySql 5
4) Tomcat 8+
5) Any REST API client to test, in this example we will use POSTMAN

In this example, we are gonna to create REST API for the employees manipulation:

1) Add Employee: http://localhost:8081/RestApi/employees/ 
2) Delete Employee: http://localhost:8081/RestApi/employees/{employeeId}
3) Update Employee: http://localhost:8081/RestApi/employees/{employeeId}
4) List Employee: http://localhost:8081/RestApi/employees/
5) Get Employee based on id: http://localhost:8081/RestApi/employees/{employeeId}

Download the project from here

So let's start the project:

Your project structure will look like:



1) Create a Maven project and keep the name RestService

Open pom.xml and copy the dependency:

<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>RestService</groupId>
  <artifactId>RestService</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  <properties>
    <java-version>1.8</java-version>
    <org.springframework-version>4.2.5.RELEASE</org.springframework-version>
    <org.aspectj-version>1.6.10</org.aspectj-version>
    <org.slf4j-version>1.6.6</org.slf4j-version>
    <failOnMissingWebXml>false</failOnMissingWebXml>
  </properties>
  
  <dependencies>
    <!-- Spring -->
    <dependency>

      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>${org.springframework-version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>${org.springframework-version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${org.springframework-version}</version>
      <exclusions>
        <!-- Exclude Commons Logging in favor of SLF4j -->
        <exclusion>
          <groupId>commons-logging</groupId>
          <artifactId>commons-logging</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${org.springframework-version}</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
    <dependency>

      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>${org.springframework-version}</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.6</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-core</artifactId>
      <version>4.1.4.Final</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-validator -->
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-validator</artifactId>
      <version>4.1.0.Final</version>
    </dependency>
   
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>${org.springframework-version}</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-orm -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-orm</artifactId>
      <version>${org.springframework-version}</version>
    </dependency> 

    <!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.0.1</version>
      <scope>provided</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>javax.servlet.jsp-api</artifactId>
      <version>2.3.1</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>   
    
    <!-- Logging -->
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>${org.slf4j-version}</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>jcl-over-slf4j</artifactId>
      <version>${org.slf4j-version}</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>${org.slf4j-version}</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.15</version>
      <exclusions>
        <exclusion>
          <groupId>javax.mail</groupId>
          <artifactId>mail</artifactId>
        </exclusion>
        <exclusion>
          <groupId>javax.jms</groupId>
          <artifactId>jms</artifactId>
        </exclusion>
        <exclusion>
          <groupId>com.sun.jdmk</groupId>
          <artifactId>jmxtools</artifactId>
        </exclusion>
        <exclusion>
          <groupId>com.sun.jmx</groupId>
          <artifactId>jmxri</artifactId>
        </exclusion>
      </exclusions>
      <scope>runtime</scope>
    </dependency>

    <!-- @Inject -->
    <dependency>
      <groupId>javax.inject</groupId>
      <artifactId>javax.inject</artifactId>
      <version>1</version>
    </dependency>

    <!-- Servlet -->
    <dependency>
      <groupId>cglib</groupId>
      <artifactId>cglib</artifactId>
      <version>2.2.2</version>
    </dependency>
    <!-- Servlet API, JSTL -->

    <dependency>
      <groupId>jstl</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>
  
  <dependency>
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-core</artifactId>
   <version>2.6.5</version>
  </dependency>
  <dependency>
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-databind</artifactId>
   <version>2.6.5</version>
  </dependency>
  
  <dependency>
   <groupId>org.codehaus.jackson</groupId>
   <artifactId>jackson-core-asl</artifactId>
   <version>1.9.13</version>
  </dependency>


    <dependency>
      <groupId>org.codehaus.jackson</groupId>
      <artifactId>jackson-mapper-asl</artifactId>
      <version>1.9.13</version>
    </dependency>
   

    
  

  </dependencies>
  <build>
    <finalName>RestApi</finalName>
  </build>
</project>       

Create an entity called Employee and paste the below code:

package com.test.domain;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="Employee")
public class Employee {

 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 @Column(name="id")
 private Integer id;
 
 @Column(name="firstName")
 private String firstName;
 
 @Column(name="lastName")
 private String lastName;
 public Integer getId() {
  return id;
 }
 public String getFirstName() {
  return firstName;
 }
 public String getLastName() {
  return lastName;
 }
 public void setId(Integer id) {
  this.id = id;
 }
 public void setFirstName(String firstName) {
  this.firstName = firstName;
 }
 public void setLastName(String lastName) {
  this.lastName = lastName;
 }
 
 
}     

Create a controller with name EmployeeController and paste the below code:

package com.test.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.test.model.EmployeeModel;
import com.test.service.EmployeeService;


@RestController
public class EmployeeController {
 
 @Autowired
 EmployeeService employeeService;

 /**
  * This method is used to list employees.
  * @return List of employees
  */
 @RequestMapping(value = "/employees", method = RequestMethod.GET)
 public ResponseEntity<List<EmployeeModel>> listEmployees(){
  List<EmployeeModel> employeeModel =  employeeService.listEmployees();
  if(employeeModel!=null){
   return new ResponseEntity<List<EmployeeModel>>(employeeModel,HttpStatus.OK); 
  }
  return new ResponseEntity<List<EmployeeModel>>(HttpStatus.NOT_FOUND);
  
 }
 
 /**
  * This method is used to get the employees based on the employee id
  * @param empId
  * @return Employee details
  */
 @RequestMapping(value = "/employees/{empId}", method = RequestMethod.GET)
 public ResponseEntity<EmployeeModel> getEmployee(@PathVariable("empId")Integer empId){
  EmployeeModel employeeModel =  employeeService.getEmployee(empId);
  if(employeeModel!=null){
   return new ResponseEntity<EmployeeModel>(employeeModel,HttpStatus.OK);
  }
  return new ResponseEntity<EmployeeModel>(HttpStatus.NOT_FOUND);
 }
 
 /**
  * This method is used to add an employee.
  * @param employee object
  * @return employee
  */
 @RequestMapping(value = "/employees", method = RequestMethod.POST)
 public ResponseEntity<EmployeeModel> addEmployee(@RequestBody EmployeeModel employeeModel){
  employeeModel =  employeeService.addEmployee(employeeModel);
  return new ResponseEntity<EmployeeModel>(employeeModel,HttpStatus.CREATED);
 }
 
 /**
  * This method is used to update employee
  * @param employee id 
  * @param employee object
  * @return employee
  */
 @RequestMapping(value = "/employees/{empId}", method = RequestMethod.PUT)
 public ResponseEntity<EmployeeModel> updateEmployee(@PathVariable("empId")Integer empId,@RequestBody EmployeeModel employeeModel){
  employeeModel.setId(empId);
  EmployeeModel updatedEmployeeModel =  employeeService.updateEmployee(employeeModel);
  return new ResponseEntity<EmployeeModel>(updatedEmployeeModel,HttpStatus.OK);
 }
 
 /**
  * This method is used to delete employee
  * @param emloyee id
  * @return
  */
 @RequestMapping(value = "/employees/{empId}", method = RequestMethod.DELETE)
 public ResponseEntity<Void> deleteEmployees(@PathVariable("empId")Integer empId){
  EmployeeModel employeeModel = employeeService.getEmployee(empId);
  if(employeeModel!=null){
   employeeService.deleteEmployee(employeeModel);
   return new ResponseEntity<Void>(HttpStatus.OK);
  }
  return new ResponseEntity<Void>(HttpStatus.NOT_FOUND);  
  
 }
}

Create a interface EmployeeService.java and add the below code.

package com.test.service;

import java.util.List;

import com.test.model.EmployeeModel;

public interface EmployeeService {

 public EmployeeModel getEmployee(Integer empId);
 public List<EmployeeModel> listEmployees();
 public EmployeeModel addEmployee(EmployeeModel employeeModel);
 public void deleteEmployee(EmployeeModel employeeModel);
 public EmployeeModel updateEmployee(EmployeeModel employeeModel);
}       

Create a class EmployeeServiceImpl.java and add the below code. This will implement the EmployeeService class.

package com.test.service;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.test.converter.EmployeeConverter;
import com.test.domain.Employee;
import com.test.model.EmployeeModel;
import com.test.repository.EmployeeRepository;

@Service
public class EmployeeServiceImpl implements EmployeeService {

 @Autowired
 private EmployeeRepository empRepository;
 
 
 @Override
 public EmployeeModel getEmployee(Integer empId) {
  return EmployeeConverter.convertToModel(empRepository.getEmployee(empId));
 }

 @Override
 public List<EmployeeModel> listEmployees() {
  List<Employee> listEmployee = empRepository.listEmployees();
  List<EmployeeModel> employeeModel = new ArrayList<EmployeeModel>();
  for(Employee employee : listEmployee){
   employeeModel.add(EmployeeConverter.convertToModel(employee));
   
  }
  return employeeModel;
 }

 @Override
 public EmployeeModel addEmployee(EmployeeModel employeeModel) {
  return EmployeeConverter.convertToModel(empRepository.addEmployee(EmployeeConverter.convertToDomain(employeeModel)));
 }

 @Override
 public void deleteEmployee(EmployeeModel employeeModel) {
  empRepository.deleteEmployee(EmployeeConverter.convertToDomain(employeeModel));
  
 }

 @Override
 public EmployeeModel updateEmployee(EmployeeModel employeeModel) {
  return EmployeeConverter.convertToModel(empRepository.updateEmployee(EmployeeConverter.convertToDomain(employeeModel)));
 }

 

}



Create a interface EmployeeRepository.java and add the below code:

package com.test.repository;

import java.util.List;

import com.test.domain.Employee;


public interface EmployeeRepository  {
 public Employee getEmployee(Integer empId);
 public List<Employee> listEmployees();
 public Employee addEmployee(Employee employeeDomain);
 public void deleteEmployee(Employee employeeDomain);
 public Employee updateEmployee(Employee employeeDomain);

}


Create a class EmployeeRepositoryImpl.java and add the below code. This class will implement the EmployeeRepository.java interface.

package com.test.repository;

import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.test.domain.Employee;

@Repository
@Transactional
public class EmployeeRepositoryImpl implements EmployeeRepository {

 @Autowired
 private SessionFactory sessionFactory;

 public void setSessionFactory(SessionFactory sf) {
  this.sessionFactory = sf;
 }
 
 

 @Override
 public Employee getEmployee(Integer empId) {
  Session session = this.sessionFactory.getCurrentSession(); 
  Employee employee = (Employee) session.get(Employee.class, empId);
  return employee;
 }

 @SuppressWarnings("unchecked")
 @Override
 public List<Employee> listEmployees() {
  Session session = this.sessionFactory.getCurrentSession();   
  List<Employee> employeeList =  session.createQuery("from Employee").list();
  return employeeList;
 }

 @Override
 public Employee addEmployee(Employee employeeDomain) {
  Session session = this.sessionFactory.getCurrentSession();
  session.save(employeeDomain);
  return employeeDomain;
 }

 @Override
 public void deleteEmployee(Employee employeeDomain) {
  Session session = this.sessionFactory.getCurrentSession(); 
  session.delete(employeeDomain);
  
 }

 @Override
 public Employee updateEmployee(Employee employeeDomain) {
  Session session = this.sessionFactory.getCurrentSession();
  Employee employee =  (Employee) session.merge(employeeDomain);
  return employee;
 }

}


In this use case, we have used java based configuration for hibernate ad spring. Create a HibernateConfiguration.java and paste the below code:

package com.test.configuration;

import java.beans.PropertyVetoException;
import java.util.Properties;

import javax.sql.DataSource;

import org.hibernate.SessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;


@Configuration
@EnableTransactionManagement
@ComponentScan({ "com.test.configuration" })
@PropertySource(value = { "classpath:application.properties" })
public class HibernateConfiguration {
 @Autowired
    private Environment environment;
 
 private static final Logger logger = LoggerFactory.getLogger(HibernateConfiguration.class);
    @Bean
    public LocalSessionFactoryBean sessionFactory() throws PropertyVetoException {
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        sessionFactory.setPackagesToScan(new String[] { "com.test.domain" });
        sessionFactory.setHibernateProperties(hibernateProperties());
        return sessionFactory;
     }
     
    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
        dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
        dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
        dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
  
        return dataSource;
    }
    
    
    private Properties hibernateProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
        properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
        properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
        properties.put("hibernate.hbm2ddl.auto", environment.getRequiredProperty("hibernate.hbm2ddl.auto"));
        properties.put("connection.autoReconnect",  environment.getRequiredProperty("connection.autoReconnect"));
        properties.put("connection.autoReconnectForPools", environment.getRequiredProperty("connection.autoReconnectForPools"));
        properties.put("connection.is-connection-validation-required", environment.getRequiredProperty("connection.is-connection-validation-required")); 
        return properties;        
    }
    
    @Bean
    @Autowired
    public HibernateTransactionManager transactionManager(SessionFactory s) {
       HibernateTransactionManager txManager = new HibernateTransactionManager();
       txManager.setSessionFactory(s);
       return txManager;
    }
}  

We are not gonna to paste all these classes here as rest of the classes are in the project. So download the project and import the same on eclipse.

Create a war and deploy the same on the tomcat server.

Let's test the APIs

1) Add an Employee: POST verb is used to add an employee.
URL: http://localhost:8081/RestApi/employees




2) Update an Employee: PUT verb is used to update an employee.
URL: http://localhost:8081/RestApi/employees/{employeeId}


3) Get an Employee: GET verb is used to get an employee.
URL: http://localhost:8081/RestApi/employees/{employeeId}



4)  List Employees: GET verb is used to list employees.
URL: http://localhost:8081/RestApi/employees



5)  Delete an Employees: DELETE verb is used to delete an employee.
URL: http://localhost:8081/RestApi/employees{employeeId}




In the next blog, you will see the how to implement OAuth2 for the REST APIs.

Thursday, 2 March 2017

Oracle Service Bus : Insert operation using Database Adapter

In the previous article, I have demonstrated how to perform select operation on the database using DB adapter. Now it's time to perform insert operation on the database. It's required almost in all the project to insert some data into the database.

Let's have a quick example, how to make this possible using the Oracle Service Bus 12c.

After this example, how must have learned to:

1) How to use DB adapter to insert data into the table
2) How to create REST service
3) How to test the DB adapter and REST service.

The basic pre-requisite to compete this example:

1) You must have Jdeveloper 12c with integrated weblogic with SOA
2) You must a Oracle database installed on your machine
3) Create a table structure, like below:



Download the project from here
Download the Emp_Details script from here

Let's have a quick steps to complete the example:

1) Create a Service Bus application with Service Bus project.
2) Project structure will like below. This is standard and you should follow the folder structure in your projects like this.


3) Let's create a outbound DB adapter. Whatever Business Service we create in the Service Bus, they are outbounds. Right click on the right swim lane and insert DB adapter.

4) Enter the Business Service Name as InsertBS and select the Service Directory as shown in the below screen:


5) Enter the JNDI name, that you have created in your weblogic console. If you don't have, then create the JDNI in the weblogic. You may follow the blog to create the JDNI in weblogic. Weblogic must be up and running to create a JNDI.

In our case, our JNDI name is eis/db/hrds. Let's enter the same and click Next button


6) In this window, Select an operation that you want to perform in your database. In our case, we are inserting the data only, so select the Perform an Operation on Table radio button and select Insert Only option.



7) This screen allows to you to select the table that you are gonna to use to insert data. In our case we do have one table called Emp_Details. Let's select the table. Click on the Import Tables button from the bottom of the wizard. Click on Query button from the opened window and select Emp_Details table, click OK




8) This window will show you the relationship with the tables if it has. Simple click Next

9) This windows allows you, what all columns you will use to insert data. Let's have as it is and click Next.


10) This window allows you to set some options. Let's leave all the default values as it is and click Next.

11) This window gives you the option to set some parameter values. You can set the values as per you need. These parameters are basically used when your business service is not reachable, and you want your service to auto retry with n number of times. Let's keep the values as it is and select Next and Finish.


Sometimes you will see the error in you project just after you create Business Service, simply refresh the project and error will go away.

Let's move the files in the respective folders as shown in the below screen:




Database adapter is ready now. You can directly test the Database adapter. Let's run the Business Service. Right click on the Business Service and click Run

Enter the values and click Execute button



Check the Emp_Details table that data have been inserted successfully or not.


Let's create REST service that will be used to send input.

Create a schema file with the below structure:

12) Let's create a inbound adapter. Right click on the left swim lane and insert REST adapter. Enter Name of the Rest Service as InsertService. Click on the + sign from the Operation Bindings section to create a operation


13) Opened window, allows you to create REST service operation. Let's name the operation InsertEmp. Select the POST from the HTTP Verb drop down. Select the Emp.xsd and select input element


14) Move to the Response tab. Check XML and JSON checkbox, if you need output in both formats else you can select any one. In our case let's check both the checkbox. Select Emp.xsd and select output element from this and click OK twice.



Proxy service is ready. Let's move the WSDL and proxy service into the respective folders.

15) It's time to insert pipeline that is your message flow. Right click in the Middle swim lane and click Pipeline. Enter Name and select Location for the pipeline. Click Next


16) In this window, select the WSDL checkbox and select the InsertService.wsdl, Uncheck the Expose as a Proxy Service click Finish



17) Wire InsertService and EmployeePipeline together. Your composite will look like after this step:



18) Let's create a XSLT transformation. XSLT will be used to convert the REST service request into the business service input. Create a XSL map and name it Emp.xsl. Select the input element of the Emp.xsd from the Primary Source section and EmpDetailsCollection element of the InsertBS_table.xsd from the Target section. Click OK


19) Map the elements like below



20) Double click on the EmployeePipeline. Drag and drop the PipelinePairNode from the component pallet. Drop the Publish activity under the Request pipeline and select the InsertBS business service as shown in the below screen shot:


In this case we have used Publish activity to call the business service. Publish activity is used when the business service doesn't return any output. It works with asynchronous services. Our InsertBS is asynchronous as it doesn't return any response.

21) Drop the Replace activity under the Publish activity. This replace activity will be used to send input to the business service.

Configure the Replace properties as:

a) Location: body
b) Value: Select XSLT Resource, select Emp.xsl that we have created in the previous step. As soon as you will select the XSLT, wizard will demand for the XSLT input. In our case, insert the the $body/exam:input expression


c) Replace Option: Select node contents option




22) Now drop the Replace activity under the Response pipeline. Enter the properties:

a) Location: body
b) Value: Select Expression and enter the expression

<output>
<status>Success</status>
</output>

c) Replace Option: Select node contents option

Your configuration is done. After this step your pipeline will look like



It's time to test the service. Right click on the REST service and click Run




Check the table that data got inserted or not.

More examples:

REST Service with DB adapter Oracle Service Bus

File adapter in Oracle Service Bus

Consume Secure SOAP service in OSB

Secure REST service in Oracle Service Bus using OWSM