Spring REST: integration tests: client y server (RestTemplate y Controller)
authorGustavo Martin Morcuende <gu.martinm@gmail.com>
Wed, 6 Jan 2016 23:16:31 +0000 (00:16 +0100)
committerGustavo Martin Morcuende <gu.martinm@gmail.com>
Fri, 8 Jan 2016 21:46:16 +0000 (22:46 +0100)
35 files changed:
SpringJava/REST/pom.xml [deleted file]
SpringJava/REST/src/doc/main/java/de/spring/webservices/rest/doc/Swagger2Configuration.java [deleted file]
SpringJava/REST/src/doc/main/resources/spring-configuration/spring-config.xml [deleted file]
SpringJava/REST/src/main/java/de/spring/webservices/rest/Car.java [deleted file]
SpringJava/REST/src/main/java/de/spring/webservices/rest/CarController.java [deleted file]
SpringJava/REST/src/main/resources/log4j2.xml [deleted file]
SpringJava/REST/src/main/resources/spring-configuration/mvc/rest/rest-config.xml [deleted file]
SpringJava/REST/src/main/resources/spring-configuration/spring-config.xml [deleted file]
SpringJava/REST/src/main/webapp/WEB-INF/web.xml [deleted file]
SpringJava/REST/src/test/java/de/spring/webservices/rest/CarControllerIntegrationTest.java [deleted file]
SpringJava/REST/web-services-spring-rest-client/pom.xml [new file with mode: 0644]
SpringJava/REST/web-services-spring-rest-client/src/doc/main/java/de/spring/webservices/rest/doc/Swagger2Configuration.java [new file with mode: 0644]
SpringJava/REST/web-services-spring-rest-client/src/doc/main/resources/spring-configuration/spring-config.xml [new file with mode: 0644]
SpringJava/REST/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/business/BusinessService.java [new file with mode: 0644]
SpringJava/REST/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/client/CarClientService.java [new file with mode: 0644]
SpringJava/REST/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/main/MainTest.java [new file with mode: 0644]
SpringJava/REST/web-services-spring-rest-client/src/main/resources/log4j2.xml [new file with mode: 0644]
SpringJava/REST/web-services-spring-rest-client/src/main/resources/rest.properties [new file with mode: 0644]
SpringJava/REST/web-services-spring-rest-client/src/main/resources/spring-configuration/rest-config.xml [new file with mode: 0644]
SpringJava/REST/web-services-spring-rest-client/src/test/java/de/spring/webservices/rest/business/BusinessServiceTest.java [new file with mode: 0644]
SpringJava/REST/web-services-spring-rest-client/src/test/java/de/spring/webservices/rest/client/CarClientServiceIntegrationTest.java [new file with mode: 0644]
SpringJava/REST/web-services-spring-rest-global/pom.xml [new file with mode: 0644]
SpringJava/REST/web-services-spring-rest-global/src/doc/main/java/de/spring/webservices/rest/doc/Swagger2Configuration.java [new file with mode: 0644]
SpringJava/REST/web-services-spring-rest-global/src/doc/main/resources/spring-configuration/spring-config.xml [new file with mode: 0644]
SpringJava/REST/web-services-spring-rest-global/src/main/java/de/spring/webservices/domain/Car.java [new file with mode: 0644]
SpringJava/REST/web-services-spring-rest-server/pom.xml [new file with mode: 0644]
SpringJava/REST/web-services-spring-rest-server/src/doc/main/java/de/spring/webservices/rest/doc/Swagger2Configuration.java [new file with mode: 0644]
SpringJava/REST/web-services-spring-rest-server/src/doc/main/resources/spring-configuration/spring-config.xml [new file with mode: 0644]
SpringJava/REST/web-services-spring-rest-server/src/main/java/de/spring/webservices/rest/CarController.java [new file with mode: 0644]
SpringJava/REST/web-services-spring-rest-server/src/main/resources/log4j2.xml [new file with mode: 0644]
SpringJava/REST/web-services-spring-rest-server/src/main/resources/spring-configuration/mvc/rest/rest-config.xml [new file with mode: 0644]
SpringJava/REST/web-services-spring-rest-server/src/main/resources/spring-configuration/spring-config.xml [new file with mode: 0644]
SpringJava/REST/web-services-spring-rest-server/src/main/webapp/WEB-INF/web.xml [new file with mode: 0644]
SpringJava/REST/web-services-spring-rest-server/src/test/java/de/spring/webservices/rest/CarControllerIntegrationTest.java [new file with mode: 0644]
SpringJava/REST/web-services-spring-rest/pom.xml [new file with mode: 0644]

diff --git a/SpringJava/REST/pom.xml b/SpringJava/REST/pom.xml
deleted file mode 100644 (file)
index 73e0eb3..0000000
+++ /dev/null
@@ -1,325 +0,0 @@
-<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/maven-v4_0_0.xsd">
-       <modelVersion>4.0.0</modelVersion>
-       <groupId>de.spring.webservices</groupId>
-       <artifactId>web-services-spring-rest</artifactId>
-       <packaging>war</packaging>
-       <version>1.0-SNAPSHOT</version>
-       <name>web-services-spring-rest</name>
-       <url>http://gumartinm.name</url>
-       <description>Web Services REST Spring Framework</description>
-       <organization>
-               <name>Gustavo Martin Morcuende</name>
-               <url>http://www.gumartinm.name</url>
-       </organization>
-       <scm>
-               <developerConnection>scm:git:http://git.gumartinm.name/JavaForFun</developerConnection>
-               <url>http://git.gumartinm.name/JavaForFun</url>
-       </scm>
-
-       <properties>
-               <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-               <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
-               <spring.version>4.2.4.RELEASE</spring.version>
-       </properties>
-
-       <profiles>
-               <profile>
-                       <id>release</id>
-                       <properties>
-                               <environment.profile>release</environment.profile>
-                       </properties>
-                       <activation>
-                               <activeByDefault>true</activeByDefault>
-                       </activation>
-               </profile>
-               <profile>
-                       <id>documentation</id>
-                       <properties>
-                               <environment.profile>documentation</environment.profile>
-                       </properties>
-                       <activation>
-                               <activeByDefault>false</activeByDefault>
-                       </activation>
-                       <dependencies>
-                               <!-- API documentation -->
-                               <dependency>
-                                       <groupId>io.springfox</groupId>
-                                       <artifactId>springfox-swagger2</artifactId>
-                                       <version>2.3.0</version>
-                               </dependency>
-                               <dependency>
-                                       <groupId>io.springfox</groupId>
-                                       <artifactId>springfox-swagger-ui</artifactId>
-                                       <version>2.3.0</version>
-                               </dependency>
-                       </dependencies>
-                       <build>
-                               <resources>
-                                       <resource>
-                                               <directory>${basedir}/src/doc/main/resources/</directory>
-                                               <includes>
-                                                       <include>**/*.*</include>
-                                               </includes>
-                                       </resource>
-                               </resources>
-                               <plugins>
-                                       <plugin>
-                                               <groupId>org.codehaus.mojo</groupId>
-                                               <artifactId>build-helper-maven-plugin</artifactId>
-                                               <version>1.10</version>
-                                               <executions>
-                                                       <execution>
-                                                               <id>add-source</id>
-                                                               <phase>process-sources</phase>
-                                                               <goals>
-                                                                       <goal>add-source</goal>
-                                                               </goals>
-                                                               <configuration>
-                                                                       <sources>
-                                                                               <source>src/doc/main/java/</source>
-                                                                       </sources>
-                                                               </configuration>
-                                                       </execution>
-                                               </executions>
-                                       </plugin>
-                               </plugins>
-                       </build>
-               </profile>
-       </profiles>
-
-       <dependencies>
-           <!--
-               1/3 Required dependency for log4j 2 with slf4j: binding between log4j 2 and slf4j
-       -->
-               <dependency>
-                       <groupId>org.apache.logging.log4j</groupId>
-                       <artifactId>log4j-slf4j-impl</artifactId>
-                       <version>2.3</version>
-               </dependency>
-               <!--
-               2/3 Required dependency for log4j 2 with slf4j: log4j 2 maven plugin (it is the log4j 2 implementation)
-       -->
-               <dependency>
-                       <groupId>org.apache.logging.log4j</groupId>
-                       <artifactId>log4j-core</artifactId>
-                       <version>2.3</version>
-               </dependency>
-               <!-- 
-                       3/3 Required dependency for getting rid of commons logging.
-                       This is the BRIDGE (no binding) between Jakarta Commons Logging (used by Spring) and whatever
-                       I am using for logging (in this case I am using log4j 2)
-                       See: http://www.slf4j.org/legacy.html
-                       
-                       We need exclusions in every dependency using Jakarta Commons Logging (see Spring dependencies below)
-                -->
-               <dependency>
-               <groupId>org.slf4j</groupId>
-               <artifactId>jcl-over-slf4j</artifactId>
-               <version>1.7.12</version>
-               </dependency>
-               
-               <dependency>
-                       <groupId>cglib</groupId>
-                       <artifactId>cglib</artifactId>
-                       <version>2.2.2</version>
-               </dependency>
-                       <dependency>
-                <groupId>org.springframework</groupId>
-                <artifactId>spring-core</artifactId>
-                <version>${spring.version}</version>
-                               <!-- 
-                                       Required dependency for getting rid of commons logging and use my own logging library
-                                       (in my case I decided to use log4j 2 under slf4j)
-                                -->
-                               <exclusions>
-                               <exclusion>
-                               <groupId>commons-logging</groupId>
-                               <artifactId>commons-logging</artifactId>
-                               </exclusion>
-                       </exclusions>
-                       </dependency>
-                       <dependency>
-                <groupId>org.springframework</groupId>
-                <artifactId>spring-webmvc</artifactId>
-                <version>${spring.version}</version>
-                               <!-- 
-                                       Required dependency for getting rid of commons logging and use my own logging library
-                                       (in my case I decided to use log4j 2 under slf4j)
-                                -->
-                               <exclusions>
-                               <exclusion>
-                               <groupId>commons-logging</groupId>
-                               <artifactId>commons-logging</artifactId>
-                               </exclusion>
-                       </exclusions>
-                       </dependency>
-
-                       <!-- Required by spring-webmvc -->
-            <dependency>
-                <groupId>javax.servlet</groupId>
-                <artifactId>javax.servlet-api</artifactId>
-                <version>4.0.0-b01</version>
-                <scope>provided</scope>
-            </dependency>
-            
-            <!-- Jackson JSON Processor, required by spring-webmvc. See messageConverters in rest-config.xml -->
-                       <dependency>
-                           <groupId>com.fasterxml.jackson.core</groupId>
-                           <artifactId>jackson-databind</artifactId>
-                           <version>2.6.4</version>
-                       </dependency>
-
-                       <!-- Required by spring-context for using JSR-303. See LocalValidatorFactoryBean in rest-config.xml -->
-                       <dependency>
-                               <groupId>javax.validation</groupId>
-                               <artifactId>validation-api</artifactId>
-                               <version>1.1.0.Final</version>
-                       </dependency>
-                       <dependency>
-                               <groupId>org.hibernate</groupId>
-                               <artifactId>hibernate-validator</artifactId>
-                               <version>5.2.2.Final</version>
-                       </dependency>
-                       
-
-                       <!-- Unitary and integration tests -->
-                       <dependency>
-                               <groupId>junit</groupId>
-                               <artifactId>junit</artifactId>
-                               <version>4.12</version>
-                               <scope>test</scope>
-                       </dependency>
-                       <dependency>
-                               <groupId>org.springframework</groupId>
-                               <artifactId>spring-test</artifactId>
-                               <version>${spring.version}</version>
-                               <scope>test</scope>
-                       </dependency>
-                       <dependency>
-                               <groupId>org.mockito</groupId>
-                               <artifactId>mockito-core</artifactId>
-                               <version>2.0.11-beta</version>
-                               <scope>test</scope>
-                       </dependency>
-
-                       <!-- Required by MockMvcResultMatchers (spring-test framework) -->
-                       <dependency>
-                               <groupId>org.hamcrest</groupId>
-                               <artifactId>hamcrest-core</artifactId>
-                               <version>1.3</version>
-                               <scope>test</scope>
-                       </dependency>
-                       <dependency>
-                               <groupId>org.hamcrest</groupId>
-                               <artifactId>hamcrest-library</artifactId>
-                               <version>1.3</version>
-                               <scope>test</scope>
-                       </dependency>
-                       <dependency>
-                               <groupId>com.jayway.jsonpath</groupId>
-                               <artifactId>json-path</artifactId>
-                               <version>2.1.0</version>
-                               <scope>test</scope>
-                       </dependency>
-                       
-       </dependencies>
-       <build>
-        <finalName>${project.artifactId}</finalName>
-        <resources>
-            <resource>
-                <directory>${basedir}/src/main/webapp</directory>
-                <excludes>
-                    <exclude>**/*.*</exclude>
-                </excludes>
-            </resource>
-            <resource>
-                <directory>${basedir}/src/main/resources/</directory>
-                <includes>
-                    <include>**/*.*</include>
-                </includes>
-            </resource>
-        </resources>
-               <plugins>
-                       <plugin>
-                               <groupId>org.apache.maven.plugins</groupId>
-                               <artifactId>maven-compiler-plugin</artifactId>
-                               <version>3.3</version>
-                               <configuration>
-                                       <source>1.8</source>
-                                       <target>1.8</target>
-                                       <encoding>${project.build.sourceEncoding}</encoding>
-                               </configuration>
-                       </plugin>
-                       <plugin>
-                               <groupId>org.apache.maven.plugins</groupId>
-                               <artifactId>maven-resources-plugin</artifactId>
-                               <version>2.7</version>
-                               <configuration>
-                                       <encoding>${project.build.sourceEncoding}</encoding>
-                               </configuration>
-                       </plugin>
-                       <plugin>
-                               <groupId>org.apache.maven.plugins</groupId>
-                               <artifactId>maven-jar-plugin</artifactId>
-                               <version>2.4</version>
-                               <configuration>
-                                       <archive>
-                                               <manifestEntries>
-                                                       <Specification-Title>${project.description}</Specification-Title>
-                                                       <Specification-Version>${project.version}</Specification-Version>
-                                                       <Specification-Vendor>${project.organization.name}</Specification-Vendor>
-                                                       <Implementation-Title>${project.description}</Implementation-Title>
-                                                       <Implementation-Version>${project.version}</Implementation-Version>
-                                                       <Implementation-Vendor>${project.organization.name}</Implementation-Vendor>
-                                               </manifestEntries>
-                                       </archive>
-                               </configuration>
-                       </plugin>
-                       <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-surefire-plugin</artifactId>
-                <version>2.18.1</version>
-                               <configuration>
-                                       <excludes>
-                                               <exclude>**/*IntegrationTest.java</exclude>
-                                       </excludes>
-                               </configuration>
-                       </plugin>
-                       <plugin>
-                               <groupId>org.apache.maven.plugins</groupId>
-                               <artifactId>maven-failsafe-plugin</artifactId>
-                <version>2.18.1</version>
-                               <executions>
-                                       <execution>
-                                               <goals>
-                                                       <goal>integration-test</goal>
-                                                       <goal>verify</goal>
-                                               </goals>
-                                       </execution>
-                               </executions>
-                               <configuration>
-                                       <includes>
-                                               <include>**/*IntegrationTest.java</include>
-                                       </includes>
-                               </configuration>
-                       </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-war-plugin</artifactId>
-                <version>2.6</version>
-                <configuration>
-                    <webResources>
-                        <resource>
-                            <filtering>true</filtering>
-                            <directory>src/main/webapp</directory>
-                            <includes>
-                                <include>WEB-INF/web.xml</include>
-                            </includes>
-                        </resource>
-                    </webResources>
-                </configuration>
-            </plugin>
-               </plugins>
-       </build>
-</project>
diff --git a/SpringJava/REST/src/doc/main/java/de/spring/webservices/rest/doc/Swagger2Configuration.java b/SpringJava/REST/src/doc/main/java/de/spring/webservices/rest/doc/Swagger2Configuration.java
deleted file mode 100644 (file)
index 98821a6..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-package de.spring.webservices.rest.doc;
-
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.web.bind.annotation.RequestMapping;
-
-import springfox.documentation.builders.ApiInfoBuilder;
-import springfox.documentation.builders.PathSelectors;
-import springfox.documentation.builders.RequestHandlerSelectors;
-import springfox.documentation.service.ApiInfo;
-import springfox.documentation.spi.DocumentationType;
-import springfox.documentation.spring.web.plugins.Docket;
-import springfox.documentation.swagger.web.UiConfiguration;
-import springfox.documentation.swagger2.annotations.EnableSwagger2;
-
-@Configuration
-@EnableSwagger2
-public class Swagger2Configuration {
-       private static final String DOCKET_ID = "web-services-spring-rest";
-       
-       @Bean
-       public Docket documentation() {
-               return new Docket(DocumentationType.SWAGGER_2)
-                               .groupName(DOCKET_ID)
-                               .select()
-                                       .apis(RequestHandlerSelectors.withMethodAnnotation(RequestMapping.class))
-                                       .paths(PathSelectors.any())
-                                       .build()
-                       .pathMapping("/")
-                       .useDefaultResponseMessages(false)
-                       .apiInfo(metadata());
-       }
-
-       @Bean
-       UiConfiguration uiConfig() {
-               return UiConfiguration.DEFAULT;
-       }
-
-       
-       private static ApiInfo metadata() {
-               return new ApiInfoBuilder()
-                               .title("gumartinm REST API")
-                               .description("Gustavo Martin Morcuende")
-                               .version("1.0-SNAPSHOT")
-                       .contact("gumartinm.name")
-                       .build();
-       }
-
-}
diff --git a/SpringJava/REST/src/doc/main/resources/spring-configuration/spring-config.xml b/SpringJava/REST/src/doc/main/resources/spring-configuration/spring-config.xml
deleted file mode 100644 (file)
index 5ca5917..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<beans xmlns="http://www.springframework.org/schema/beans"
-       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-       xmlns:context="http://www.springframework.org/schema/context"
-       xmlns:util="http://www.springframework.org/schema/util"
-       xsi:schemaLocation="http://www.springframework.org/schema/beans
-        http://www.springframework.org/schema/beans/spring-beans.xsd
-        http://www.springframework.org/schema/context
-        http://www.springframework.org/schema/context/spring-context.xsd
-        http://www.springframework.org/schema/util
-        http://www.springframework.org/schema/util/spring-util.xsd">
-
-       <!--
-       
-       Local deployment URLs:
-       
-       Swagger:
-       http://localhost:8080/web-services-spring-rest/spring-rest/v2/api-docs?group=web-services-spring-rest
-       
-       Swagger-UI:
-       http://localhost:8080/web-services-spring-rest/swagger-ui.html
-       
-       -->
-
-    <bean class="de.spring.webservices.rest.doc.Swagger2Configuration"/>
-
-</beans>
diff --git a/SpringJava/REST/src/main/java/de/spring/webservices/rest/Car.java b/SpringJava/REST/src/main/java/de/spring/webservices/rest/Car.java
deleted file mode 100644 (file)
index 4310f9d..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-package de.spring.webservices.rest;
-
-public class Car {
-
-    private final Long id;
-    private final String content;
-
-    // Required by Jackson :/
-    public Car() {
-       this.id = null;
-       this.content = null;
-    }
-    
-    public Car(Long id, String content) {
-        this.id = id;
-        this.content = content;
-    }
-
-    public Long getId() {
-        return id;
-    }
-
-    public String getContent() {
-        return content;
-    }
-}
diff --git a/SpringJava/REST/src/main/java/de/spring/webservices/rest/CarController.java b/SpringJava/REST/src/main/java/de/spring/webservices/rest/CarController.java
deleted file mode 100644 (file)
index ceafb42..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-package de.spring.webservices.rest;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicLong;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
-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.RequestHeader;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.ResponseStatus;
-import org.springframework.web.bind.annotation.RestController;
-
-//import io.swagger.annotations.ApiOperation;
-//import io.swagger.annotations.ApiResponse;
-//import io.swagger.annotations.ApiResponses;
-
-@RestController
-@RequestMapping("/api/cars/")
-public class CarController {
-       private static final Logger LOGGER = LoggerFactory.getLogger(CarController.class);
-    private static final String TEMPLATE = "Car: %s";
-    
-    private final AtomicLong counter = new AtomicLong();
-
-//  Do I want to release with Swagger dependencies?
-//    @ApiOperation(value = "getCars", nickname = "getAllCars", response = Car.class)
-//    @ApiResponses({
-//        @ApiResponse(code =  404, message ="Not found"),
-//        @ApiResponse(code =  400, message ="Invalid input")
-//    })
-    @RequestMapping(produces = { MediaType.APPLICATION_JSON_UTF8_VALUE }, method = RequestMethod.GET)
-    @ResponseStatus(HttpStatus.OK)
-    public List<Car> cars() {
-        final List<Car> cars = new ArrayList<>();
-        cars.add(new Car(counter.incrementAndGet(), String.format(TEMPLATE, 1)));
-        cars.add(new Car(counter.incrementAndGet(), String.format(TEMPLATE, 2)));
-        cars.add(new Car(counter.incrementAndGet(), String.format(TEMPLATE, 3)));
-
-        return cars;
-    }
-
-//  Do I want to release with Swagger dependencies?
-//  @ApiOperation(value = "getCar", nickname = "getsOneCar", response = Car.class)
-//  @ApiResponses({
-//      @ApiResponse(code =  404, message ="Not found"),
-//      @ApiResponse(code =  400, message ="Invalid input")
-//  })
-    @RequestMapping(value = "{id}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.GET)
-    @ResponseStatus(HttpStatus.OK)
-    public Car car(@RequestHeader(value = "MY_HEADER", required = false) String specialHeader,
-               @PathVariable("id") long id,
-               @RequestParam Map<String, String> params,
-               @RequestParam(value = "wheel", required = false) String[] wheelParams) {
-               
-       if (specialHeader != null) {
-               LOGGER.info("SPECIAL HEADER: " + specialHeader);
-       }
-        
-       if (params.get("mirror") != null) {
-               LOGGER.info("MIRROR: " + params.get("mirror")); 
-       }
-       
-       if (params.get("window") != null) {
-               LOGGER.info("WINDOW: " + params.get("window"));
-       }
-       
-       if (wheelParams != null) {
-               for(String wheel : wheelParams) {
-                       LOGGER.info(wheel);
-               }
-       }
-       
-        try {
-            Thread.sleep(10000);                 //1000 milliseconds is one second.
-        } catch(InterruptedException ex) {
-            Thread.currentThread().interrupt();
-        }
-
-
-        return new Car(counter.incrementAndGet(), String.format(TEMPLATE, id));
-    }
-    
-//  Do I want to release with Swagger dependencies?
-//  @ApiOperation(value = "postCat", nickname = "createsNewCar", response = Car.class)
-//  @ApiResponses({
-//      @ApiResponse(code =  404, message ="Not found"),
-//      @ApiResponse(code =  400, message ="Invalid input")
-//  })
-    @RequestMapping(consumes = MediaType.APPLICATION_JSON_UTF8_VALUE,
-               produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.POST)
-    public ResponseEntity<Car> create(@RequestBody Car car) {
-       long count = counter.incrementAndGet();
-       HttpHeaders headers = new HttpHeaders();
-       headers.add(HttpHeaders.LOCATION, "/api/cars/" + count);
-       
-        return new ResponseEntity<>(new Car(count, String.format(TEMPLATE, count)), headers, HttpStatus.CREATED);
-    }
-
-}
diff --git a/SpringJava/REST/src/main/resources/log4j2.xml b/SpringJava/REST/src/main/resources/log4j2.xml
deleted file mode 100644 (file)
index ee36b97..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!-- 
-       status: The level of internal Log4j events that should be logged to the console.
-       Valid values for this attribute are "trace", "debug", "info", "warn", "error" and "fatal".
-       
-       monitorInterval: The minimum amount of time, in seconds, that must elapse before the file configuration is checked for changes.
-       
-       
-       see https://logging.apache.org/log4j/2.x/manual/configuration.html
- -->
-<Configuration status="error" strict="true" monitorInterval="30"
-                name="XMLConfigTest" packages="org.apache.logging.log4j.test">
-                
-       <!--
-               ALL > TRACE > DEBUG > INFO > WARN > ERROR > OFF
-               
-               ERROR by default.
-       -->
-                
-    <Appenders>
-        <Appender type="Console" name="STDOUT">
-            <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
-        </Appender>
-    </Appenders>
-    <Loggers>
-    
-        <!-- 
-               Specific log level for Spring WEBMVC.
-        -->
-        <Logger name="org.springframework.web" level="INFO" additivity="false">
-            <AppenderRef ref="STDOUT" />
-        </Logger>
-    
-    
-               <!-- 
-               General logging Spring.
-        -->
-        <Logger name="org.springframework" level="INFO" additivity="false">
-            <AppenderRef ref="STDOUT" />
-        </Logger>
-    
-
-               <!-- 
-                       Anything else will be using TRACE logging level.
-                -->        
-        <Root level="INFO">
-            <AppenderRef ref="STDOUT"/>
-        </Root>
-        
-    </Loggers>
-</Configuration>
diff --git a/SpringJava/REST/src/main/resources/spring-configuration/mvc/rest/rest-config.xml b/SpringJava/REST/src/main/resources/spring-configuration/mvc/rest/rest-config.xml
deleted file mode 100644 (file)
index bed7947..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-<beans xmlns="http://www.springframework.org/schema/beans"
-       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-       xmlns:mvc="http://www.springframework.org/schema/mvc"
-       xmlns:context="http://www.springframework.org/schema/context"
-       xmlns:util="http://www.springframework.org/schema/util"
-       xmlns:p="http://www.springframework.org/schema/p"
-       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
-        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
-        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
-        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
-   
-       <!--
-               I am declaring my beans without the automatic annotation. :/
-               Better because we are saving memory but it requires more configuration.
-               
-               See: org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser
-               <mvc:annotation-driven/>
-        -->
-        
-   
-       <context:annotation-config />
-   
-       <context:component-scan base-package="de.spring.webservices.rest"/>
-
-    <bean id="jsonObjectMapperFactory" class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean" p:indentOutput="true" p:failOnEmptyBeans="false">
-        <property name="featuresToDisable">
-            <array>
-                <util:constant static-field="com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES"/>
-                <util:constant static-field="com.fasterxml.jackson.databind.MapperFeature.DEFAULT_VIEW_INCLUSION"/>
-            </array>
-        </property>
-    </bean>
-
-    <util:list id="messageConverters">
-        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" p:objectMapper-ref="jsonObjectMapperFactory"/>
-        <bean class="org.springframework.http.converter.StringHttpMessageConverter" />
-    </util:list>
-
-
-       <bean name="handlerAdapter"
-               class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
-               <property name="webBindingInitializer">
-                       <bean
-                               class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
-                               <!-- It enables us to use JSR-303 -->
-                               <property name="validator">
-                                       <bean class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
-                               </property>
-                       </bean>
-               </property>
-               <property name="messageConverters" ref="messageConverters" />
-               
-               
-               <property name="requestBodyAdvice">
-                       <util:list>
-                               <bean id="requestBodyAdvice" class="org.springframework.web.servlet.mvc.method.annotation.JsonViewRequestBodyAdvice"/>
-                       </util:list>
-               </property>
-               
-               
-               <property name="responseBodyAdvice">
-                       <util:list>
-                               <bean id="responseBodyAdvice" class="org.springframework.web.servlet.mvc.method.annotation.JsonViewResponseBodyAdvice"/>
-                       </util:list>
-               </property>
-       </bean>
-    
-       <bean id="handlerMapping" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
-
-       <mvc:default-servlet-handler />
-       
-</beans>
diff --git a/SpringJava/REST/src/main/resources/spring-configuration/spring-config.xml b/SpringJava/REST/src/main/resources/spring-configuration/spring-config.xml
deleted file mode 100644 (file)
index af3643b..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<beans xmlns="http://www.springframework.org/schema/beans"
-       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-       xmlns:context="http://www.springframework.org/schema/context"
-       xmlns:util="http://www.springframework.org/schema/util"
-       xsi:schemaLocation="http://www.springframework.org/schema/beans
-        http://www.springframework.org/schema/beans/spring-beans.xsd
-        http://www.springframework.org/schema/context
-        http://www.springframework.org/schema/context/spring-context.xsd
-        http://www.springframework.org/schema/util
-        http://www.springframework.org/schema/util/spring-util.xsd">
-
-</beans>
diff --git a/SpringJava/REST/src/main/webapp/WEB-INF/web.xml b/SpringJava/REST/src/main/webapp/WEB-INF/web.xml
deleted file mode 100644 (file)
index 26089bd..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
-         version="2.4">
-
-    <display-name>Spring REST Services: example</display-name>
-
-    <listener>
-        <listener-class>
-            org.springframework.web.context.ContextLoaderListener
-        </listener-class>
-    </listener>
-
-    <context-param>
-        <param-name>spring.profiles.active</param-name>
-        <param-value>${environment.profile}</param-value>
-        <param-name>contextConfigLocation</param-name>
-        <param-value>
-            classpath*:spring-configuration/*.xml
-        </param-value>
-    </context-param>
-    
-    <!-- Spring REST support -->
-    <servlet>
-        <servlet-name>spring-rest</servlet-name>
-        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
-        <load-on-startup>1</load-on-startup>
-        <async-supported>true</async-supported>
-        <init-param>
-           <param-name>contextConfigLocation</param-name>
-           <param-value>classpath*:spring-configuration/mvc/rest/*.xml</param-value>
-        </init-param>
-    </servlet>
-
-    <servlet-mapping>
-        <servlet-name>spring-rest</servlet-name>
-        <url-pattern>/spring-rest/*</url-pattern>
-    </servlet-mapping>
-
-</web-app>
diff --git a/SpringJava/REST/src/test/java/de/spring/webservices/rest/CarControllerIntegrationTest.java b/SpringJava/REST/src/test/java/de/spring/webservices/rest/CarControllerIntegrationTest.java
deleted file mode 100644 (file)
index 090d2c4..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-package de.spring.webservices.rest;
-
-import static org.hamcrest.Matchers.any;
-import static org.hamcrest.Matchers.is;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
-import org.springframework.test.context.ContextConfiguration;
-import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
-import org.springframework.test.web.servlet.MockMvc;
-import org.springframework.test.web.servlet.setup.MockMvcBuilders;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-
-@RunWith(SpringJUnit4ClassRunner.class)
-@ContextConfiguration({ "classpath*:spring-configuration/mvc/rest/*.xml"})
-public class CarControllerIntegrationTest {
-       private CarController controller;
-       private MockMvc mockMvc;
-       
-    @Before
-    public void setup() {
-       controller = new CarController();
-        mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
-    }
-
-       @Test
-       public void testWhenGetAllCarsThenRetrieveJsonValues() throws Exception {
-               mockMvc.perform(get("/api/cars/")
-                               .accept(MediaType.APPLICATION_JSON_UTF8))
-               
-               .andExpect(status().isOk())
-               .andExpect(jsonPath("$[0].id", any(Integer.class)))
-               .andExpect(jsonPath("$[0].content", is("Car: 1")))
-               .andExpect(jsonPath("$[1].content", is("Car: 2")))
-               .andExpect(jsonPath("$[1].id", any(Integer.class)))
-               .andExpect(jsonPath("$[2].content", is("Car: 3")))
-               .andExpect(jsonPath("$[2].id", any(Integer.class)))
-               .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8));
-       }
-       
-       @Test
-       public void testWhenGetOneCarThenRetrieveJsonValue() throws Exception {
-               mockMvc.perform(get("/api/cars/{id}", 1L)
-                               .accept(MediaType.APPLICATION_JSON_UTF8))
-       
-               .andExpect(status().isOk())
-               .andExpect(jsonPath("id", any(Integer.class)))
-               .andExpect(jsonPath("content", is("Car: 1")))
-               .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8));
-       }
-       
-       @Test
-       public void testWhenCreateNewCarThenRetrieveJsonValue() throws Exception {
-               Car car = new Car(2L, "nothing");
-               mockMvc.perform(post("/api/cars/")
-                               .contentType(MediaType.APPLICATION_JSON_UTF8)
-                               .content(asJsonString(car))
-                               .accept(MediaType.APPLICATION_JSON_UTF8))
-               
-               .andExpect(status().isCreated())
-               .andExpect(jsonPath("id", any(Integer.class)))
-               .andExpect(jsonPath("content", is("Car: 1")))
-               .andExpect(header().string(HttpHeaders.LOCATION, "/api/cars/1"))
-               .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8));
-       }
-       
-       private static String asJsonString(final Object obj) throws JsonProcessingException {
-               final ObjectMapper mapper = new ObjectMapper();
-               return mapper.writeValueAsString(obj);
-       }
-}
diff --git a/SpringJava/REST/web-services-spring-rest-client/pom.xml b/SpringJava/REST/web-services-spring-rest-client/pom.xml
new file mode 100644 (file)
index 0000000..276b3db
--- /dev/null
@@ -0,0 +1,61 @@
+<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/maven-v4_0_0.xsd">
+       <modelVersion>4.0.0</modelVersion>
+       <parent>
+               <artifactId>web-services-spring-rest</artifactId>
+               <groupId>de.spring.webservices</groupId>
+               <version>1.0-SNAPSHOT</version>
+       </parent>
+       <artifactId>web-services-spring-rest-client</artifactId>
+       <name>web-services-spring-rest-client</name>
+       <url>http://gumartinm.name</url>
+       <dependencies>
+               <dependency>
+                       <groupId>de.spring.webservices</groupId>
+                       <artifactId>web-services-spring-rest-global</artifactId>
+                       <version>1.0-SNAPSHOT</version>
+               </dependency>
+       
+               <dependency>
+                       <groupId>org.springframework</groupId>
+                       <artifactId>spring-core</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.springframework</groupId>
+                       <artifactId>spring-webmvc</artifactId>
+               </dependency>
+               
+               <!-- Jackson JSON Processor, required by spring-webmvc. See messageConverters in rest-config.xml -->
+               <dependency>
+                       <groupId>com.fasterxml.jackson.core</groupId>
+                       <artifactId>jackson-databind</artifactId>
+               </dependency>
+               
+               <!-- Unitary and integration tests -->
+               <dependency>
+                       <groupId>junit</groupId>
+                       <artifactId>junit</artifactId>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.springframework</groupId>
+                       <artifactId>spring-test</artifactId>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.mockito</groupId>
+                       <artifactId>mockito-core</artifactId>
+                       <scope>test</scope>
+               </dependency>
+       </dependencies>
+       <build>
+               <resources>
+                       <resource>
+                               <directory>${basedir}/src/main/resources/</directory>
+                               <includes>
+                                       <include>**/*.*</include>
+                               </includes>
+                       </resource>
+               </resources>
+       </build>
+</project>
\ No newline at end of file
diff --git a/SpringJava/REST/web-services-spring-rest-client/src/doc/main/java/de/spring/webservices/rest/doc/Swagger2Configuration.java b/SpringJava/REST/web-services-spring-rest-client/src/doc/main/java/de/spring/webservices/rest/doc/Swagger2Configuration.java
new file mode 100644 (file)
index 0000000..6e0de24
--- /dev/null
@@ -0,0 +1,52 @@
+package de.spring.webservices.rest.doc;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger.web.UiConfiguration;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+@Configuration
+@EnableWebMvc
+@EnableSwagger2
+public class Swagger2Configuration {
+       private static final String DOCKET_ID = "web-services-spring-rest";
+       
+       @Bean
+       public Docket documentation() {
+               return new Docket(DocumentationType.SWAGGER_2)
+                               .groupName(DOCKET_ID)
+                               .select()
+                                       .apis(RequestHandlerSelectors.withMethodAnnotation(RequestMapping.class))
+                                       .paths(PathSelectors.any())
+                                       .build()
+                       .pathMapping("/")
+                       .useDefaultResponseMessages(false)
+                       .apiInfo(metadata())
+                       .enable(true);
+       }
+
+       @Bean
+       UiConfiguration uiConfig() {
+               return UiConfiguration.DEFAULT;
+       }
+
+       
+       private static ApiInfo metadata() {
+               return new ApiInfoBuilder()
+                               .title("gumartinm REST API")
+                               .description("Gustavo Martin Morcuende")
+                               .version("1.0-SNAPSHOT")
+                       .contact("gumartinm.name")
+                       .build();
+       }
+
+}
diff --git a/SpringJava/REST/web-services-spring-rest-client/src/doc/main/resources/spring-configuration/spring-config.xml b/SpringJava/REST/web-services-spring-rest-client/src/doc/main/resources/spring-configuration/spring-config.xml
new file mode 100644 (file)
index 0000000..5ca5917
--- /dev/null
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:context="http://www.springframework.org/schema/context"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+        http://www.springframework.org/schema/beans/spring-beans.xsd
+        http://www.springframework.org/schema/context
+        http://www.springframework.org/schema/context/spring-context.xsd
+        http://www.springframework.org/schema/util
+        http://www.springframework.org/schema/util/spring-util.xsd">
+
+       <!--
+       
+       Local deployment URLs:
+       
+       Swagger:
+       http://localhost:8080/web-services-spring-rest/spring-rest/v2/api-docs?group=web-services-spring-rest
+       
+       Swagger-UI:
+       http://localhost:8080/web-services-spring-rest/swagger-ui.html
+       
+       -->
+
+    <bean class="de.spring.webservices.rest.doc.Swagger2Configuration"/>
+
+</beans>
diff --git a/SpringJava/REST/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/business/BusinessService.java b/SpringJava/REST/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/business/BusinessService.java
new file mode 100644 (file)
index 0000000..9f76052
--- /dev/null
@@ -0,0 +1,49 @@
+package de.spring.webservices.rest.business;
+
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import de.spring.webservices.domain.Car;
+import de.spring.webservices.rest.client.CarClientService;
+
+@Service("businessService")
+public class BusinessService {
+       private static final Logger LOGGER = LoggerFactory.getLogger(BusinessService.class);
+
+       private final CarClientService carClientService;
+
+       @Autowired
+       public BusinessService(CarClientService carClientService) {
+               this.carClientService = carClientService;
+       }
+       
+       
+       public void doSomethingWithCars() {
+               List<Car> cars = carClientService.doGetCars();
+               LOGGER.info("Retrieved cars");
+               for (Car car : cars) {
+                       LOGGER.info("car: " + car.getId());
+                       LOGGER.info(car.getContent());
+               }
+       }
+       
+       public void doSomethingWithCar(long id) {               
+               Car car = carClientService.doGetCar(id);
+               LOGGER.info("Retrieved car");
+               LOGGER.info("car: " + car.getId());
+               LOGGER.info(car.getContent());
+       }
+       
+       public void createsNewCar() {
+               Car newCar = new Car(666L, "just_a_test");
+               
+               Car car = carClientService.doNewCar(newCar);
+               LOGGER.info("New car");
+               LOGGER.info("car: " + car.getId());
+               LOGGER.info(car.getContent());
+       }
+}
diff --git a/SpringJava/REST/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/client/CarClientService.java b/SpringJava/REST/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/client/CarClientService.java
new file mode 100644 (file)
index 0000000..2d2e2da
--- /dev/null
@@ -0,0 +1,55 @@
+package de.spring.webservices.rest.client;
+
+import java.net.URI;
+import java.util.Arrays;
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+
+import de.spring.webservices.domain.Car;
+
+@Service("carClientService")
+public class CarClientService {
+       private static final Logger LOGGER = LoggerFactory.getLogger(CarClientService.class);
+
+       private final String apiCarsUrl;
+       private final String apiCarUrl;
+       private final RestTemplate restTemplate;
+       
+    @Autowired
+       public CarClientService(@Value("${url.base}${url.cars}") String apiCarsUrl,
+                       @Value("${url.base}${url.car}") String apiCarUrl, RestTemplate restTemplate) {
+               this.apiCarsUrl = apiCarsUrl;
+               this.apiCarUrl = apiCarUrl;
+               this.restTemplate = restTemplate;
+       }
+
+       
+       public List<Car> doGetCars() {                          
+               ResponseEntity<Car[]> responseEntity = restTemplate.getForEntity(apiCarsUrl, Car[].class);
+               
+               return Arrays.asList(responseEntity.getBody());
+       }
+       
+       public Car doGetCar(long id) {                          
+               ResponseEntity<Car> responseEntity = restTemplate.getForEntity(
+                               apiCarUrl.replace(":id", String.valueOf(id)), Car.class);
+               
+               return responseEntity.getBody();
+       }
+       
+
+       public Car doNewCar(Car car) {          
+               ResponseEntity<Car> responseEntity = restTemplate.postForEntity(apiCarsUrl, car, Car.class);
+               URI newCarLocation = responseEntity.getHeaders().getLocation();
+               LOGGER.info("new car location: " + newCarLocation.getPath());
+                       
+               return responseEntity.getBody();
+       }
+}
diff --git a/SpringJava/REST/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/main/MainTest.java b/SpringJava/REST/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/main/MainTest.java
new file mode 100644 (file)
index 0000000..721a58b
--- /dev/null
@@ -0,0 +1,35 @@
+package de.spring.webservices.rest.main;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+import de.spring.webservices.rest.business.BusinessService;
+
+
+/**
+ * This class is used just like a nice example about how to write and run client
+ * code which will send data to and from the Web Services.
+ * 
+ */
+public class MainTest {        
+    public ApplicationContext context;
+
+    /**
+     * @param args
+     */
+    public static void main(final String[] args) {
+        final MainTest test = new MainTest();
+
+        test.context = new ClassPathXmlApplicationContext(
+                "classpath:spring-configuration/rest-config.xml");
+
+        final BusinessService example =
+                       (BusinessService) test.context.getBean("businessService");
+        
+        example.doSomethingWithCars();
+        
+        example.doSomethingWithCar(66L);
+        
+        example.createsNewCar();
+    }
+}
diff --git a/SpringJava/REST/web-services-spring-rest-client/src/main/resources/log4j2.xml b/SpringJava/REST/web-services-spring-rest-client/src/main/resources/log4j2.xml
new file mode 100644 (file)
index 0000000..ee36b97
--- /dev/null
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- 
+       status: The level of internal Log4j events that should be logged to the console.
+       Valid values for this attribute are "trace", "debug", "info", "warn", "error" and "fatal".
+       
+       monitorInterval: The minimum amount of time, in seconds, that must elapse before the file configuration is checked for changes.
+       
+       
+       see https://logging.apache.org/log4j/2.x/manual/configuration.html
+ -->
+<Configuration status="error" strict="true" monitorInterval="30"
+                name="XMLConfigTest" packages="org.apache.logging.log4j.test">
+                
+       <!--
+               ALL > TRACE > DEBUG > INFO > WARN > ERROR > OFF
+               
+               ERROR by default.
+       -->
+                
+    <Appenders>
+        <Appender type="Console" name="STDOUT">
+            <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
+        </Appender>
+    </Appenders>
+    <Loggers>
+    
+        <!-- 
+               Specific log level for Spring WEBMVC.
+        -->
+        <Logger name="org.springframework.web" level="INFO" additivity="false">
+            <AppenderRef ref="STDOUT" />
+        </Logger>
+    
+    
+               <!-- 
+               General logging Spring.
+        -->
+        <Logger name="org.springframework" level="INFO" additivity="false">
+            <AppenderRef ref="STDOUT" />
+        </Logger>
+    
+
+               <!-- 
+                       Anything else will be using TRACE logging level.
+                -->        
+        <Root level="INFO">
+            <AppenderRef ref="STDOUT"/>
+        </Root>
+        
+    </Loggers>
+</Configuration>
diff --git a/SpringJava/REST/web-services-spring-rest-client/src/main/resources/rest.properties b/SpringJava/REST/web-services-spring-rest-client/src/main/resources/rest.properties
new file mode 100644 (file)
index 0000000..00255b0
--- /dev/null
@@ -0,0 +1,4 @@
+url.base = http://localhost:8080/web-services-spring-rest-server/spring-rest/
+
+url.cars = api/cars/
+url.car = api/cars/:id
\ No newline at end of file
diff --git a/SpringJava/REST/web-services-spring-rest-client/src/main/resources/spring-configuration/rest-config.xml b/SpringJava/REST/web-services-spring-rest-client/src/main/resources/spring-configuration/rest-config.xml
new file mode 100644 (file)
index 0000000..5f4e873
--- /dev/null
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:context="http://www.springframework.org/schema/context"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xmlns:p="http://www.springframework.org/schema/p"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+        http://www.springframework.org/schema/beans/spring-beans.xsd
+        http://www.springframework.org/schema/context
+        http://www.springframework.org/schema/context/spring-context.xsd
+        http://www.springframework.org/schema/util
+        http://www.springframework.org/schema/util/spring-util.xsd">
+       
+          
+       <context:annotation-config />
+   
+       <context:component-scan base-package="de.spring.webservices.rest"/>
+       
+       <context:property-placeholder location="classpath:rest.properties" />
+       
+       <bean id="jsonObjectMapperFactory" class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean" p:indentOutput="true" p:failOnEmptyBeans="false">
+        <property name="featuresToDisable">
+            <array>
+                <util:constant static-field="com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES"/>
+                <util:constant static-field="com.fasterxml.jackson.databind.MapperFeature.DEFAULT_VIEW_INCLUSION"/>
+            </array>
+        </property>
+    </bean>
+
+    <util:list id="messageConverters">
+        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" p:objectMapper-ref="jsonObjectMapperFactory"/>
+        <bean class="org.springframework.http.converter.StringHttpMessageConverter" />
+    </util:list>
+    
+       <bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
+                   <constructor-arg ref="messageConverters" />
+       </bean>
+       
+</beans>
diff --git a/SpringJava/REST/web-services-spring-rest-client/src/test/java/de/spring/webservices/rest/business/BusinessServiceTest.java b/SpringJava/REST/web-services-spring-rest-client/src/test/java/de/spring/webservices/rest/business/BusinessServiceTest.java
new file mode 100644 (file)
index 0000000..3910f0b
--- /dev/null
@@ -0,0 +1,54 @@
+package de.spring.webservices.rest.business;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import de.spring.webservices.domain.Car;
+import de.spring.webservices.rest.client.CarClientService;
+
+public class BusinessServiceTest {
+
+       private CarClientService carClientService;
+       private BusinessService businessService;
+       
+    @Before
+    public void createTest() {
+       carClientService = mock(CarClientService.class);
+       businessService = new BusinessService(carClientService);        
+    }
+    
+       @Test
+       public void whenDoSomethingWithCarsThenInvokeDoGetCars() {
+               Car expectedOne = new Car(66L, "test");
+               Car expectedTwo = new Car(99L, "example");
+               List<Car> expected = new ArrayList<>();
+               expected.add(expectedOne);
+               expected.add(expectedTwo);
+               when(carClientService.doGetCars()).thenReturn(expected);
+               
+               businessService.doSomethingWithCars();
+               
+               verify(carClientService, times(1)).doGetCars();
+       }
+
+    
+       @Test
+       public void whenDoSomethingWithOneCarhenInvokeDoGetCar() {
+               Long id = 66L;
+               Car expected = new Car(66L, "test");
+               
+               when(carClientService.doGetCar(id)).thenReturn(expected);
+               
+               businessService.doSomethingWithCar(id);
+               
+               verify(carClientService, times(1)).doGetCar(id);
+       }
+}
diff --git a/SpringJava/REST/web-services-spring-rest-client/src/test/java/de/spring/webservices/rest/client/CarClientServiceIntegrationTest.java b/SpringJava/REST/web-services-spring-rest-client/src/test/java/de/spring/webservices/rest/client/CarClientServiceIntegrationTest.java
new file mode 100644 (file)
index 0000000..65d752a
--- /dev/null
@@ -0,0 +1,115 @@
+package de.spring.webservices.rest.client;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
+import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
+import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.web.client.MockRestServiceServer;
+import org.springframework.web.client.RestTemplate;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import de.spring.webservices.domain.Car;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration("classpath*:spring-configuration/rest-config.xml")
+public class CarClientServiceIntegrationTest {
+       
+       @Value("${url.base}${url.cars}")
+       private String apiCarsUrl;
+       
+       @Value("${url.base}${url.car}")
+       private String apiCarUrl;
+       
+    @Autowired
+    private RestTemplate restTemplate;
+    
+    @Autowired
+       private CarClientService carClientService;
+
+    private MockRestServiceServer mockServer;
+
+    @Before
+    public void createTest() {
+        mockServer = MockRestServiceServer.createServer(restTemplate);
+    }
+
+       @Test
+       public void whenGetAllCarsThenRetrieveRequestedCars() throws JsonProcessingException {
+               Car expectedOne = new Car(66L, "test");
+               Car expectedTwo = new Car(99L, "example");
+               List<Car> expected = new ArrayList<>();
+               expected.add(expectedOne);
+               expected.add(expectedTwo);
+               
+               mockServer.expect(requestTo(apiCarsUrl))
+                                       .andExpect(method(HttpMethod.GET))
+                                       .andRespond(withSuccess(asJsonString(expected), MediaType.APPLICATION_JSON_UTF8));
+
+               List<Car> cars = carClientService.doGetCars();
+
+               mockServer.verify();
+               
+               assertEquals(2, cars.size());
+               assertEquals(expectedOne, cars.get(0));
+               assertEquals(expectedTwo, cars.get(1));
+       }
+       
+       @Test
+       public void whenGetCarByIdThenRetrieveRequestedCar() throws JsonProcessingException {
+               Long id = 66L;
+               Car expected = new Car(66L, "test");
+               
+               mockServer.expect(requestTo(apiCarUrl.replace(":id", String.valueOf(id))))
+                                       .andExpect(method(HttpMethod.GET))
+                                       .andRespond(withSuccess(asJsonString(expected), MediaType.APPLICATION_JSON_UTF8));
+
+               Car car = carClientService.doGetCar(id);
+
+               mockServer.verify();
+               
+               assertNotNull(car);
+               assertEquals(expected, car);
+       }
+       
+       @Test
+       public void whenCreateNewCarThenRetrieveCreatedCar() throws JsonProcessingException {
+               Long expectedId = 66L;
+               HttpHeaders headers = new HttpHeaders();
+               headers.add(HttpHeaders.LOCATION, "/api/cars/" + String.valueOf(expectedId));
+               Car expected = new Car(expectedId, "test");
+               
+               mockServer.expect(requestTo(apiCarsUrl))
+                                       .andExpect(method(HttpMethod.POST))
+                                       .andRespond(withSuccess(asJsonString(expected), MediaType.APPLICATION_JSON_UTF8)
+                                                       .headers(headers));
+
+               Car car = carClientService.doNewCar(expected);
+
+               mockServer.verify();
+               
+               assertNotNull(car);
+               assertEquals(expected, car);
+       }
+       
+       private static String asJsonString(final Object obj) throws JsonProcessingException {
+               final ObjectMapper mapper = new ObjectMapper();
+               return mapper.writeValueAsString(obj);
+       }
+}
diff --git a/SpringJava/REST/web-services-spring-rest-global/pom.xml b/SpringJava/REST/web-services-spring-rest-global/pom.xml
new file mode 100644 (file)
index 0000000..c726115
--- /dev/null
@@ -0,0 +1,12 @@
+<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/maven-v4_0_0.xsd">
+       <modelVersion>4.0.0</modelVersion>
+       <parent>
+               <artifactId>web-services-spring-rest</artifactId>
+               <groupId>de.spring.webservices</groupId>
+               <version>1.0-SNAPSHOT</version>
+       </parent>
+       <artifactId>web-services-spring-rest-global</artifactId>
+       <name>web-services-spring-rest-global</name>
+       <url>http://gumartinm.name</url>
+</project>
diff --git a/SpringJava/REST/web-services-spring-rest-global/src/doc/main/java/de/spring/webservices/rest/doc/Swagger2Configuration.java b/SpringJava/REST/web-services-spring-rest-global/src/doc/main/java/de/spring/webservices/rest/doc/Swagger2Configuration.java
new file mode 100644 (file)
index 0000000..6e0de24
--- /dev/null
@@ -0,0 +1,52 @@
+package de.spring.webservices.rest.doc;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger.web.UiConfiguration;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+@Configuration
+@EnableWebMvc
+@EnableSwagger2
+public class Swagger2Configuration {
+       private static final String DOCKET_ID = "web-services-spring-rest";
+       
+       @Bean
+       public Docket documentation() {
+               return new Docket(DocumentationType.SWAGGER_2)
+                               .groupName(DOCKET_ID)
+                               .select()
+                                       .apis(RequestHandlerSelectors.withMethodAnnotation(RequestMapping.class))
+                                       .paths(PathSelectors.any())
+                                       .build()
+                       .pathMapping("/")
+                       .useDefaultResponseMessages(false)
+                       .apiInfo(metadata())
+                       .enable(true);
+       }
+
+       @Bean
+       UiConfiguration uiConfig() {
+               return UiConfiguration.DEFAULT;
+       }
+
+       
+       private static ApiInfo metadata() {
+               return new ApiInfoBuilder()
+                               .title("gumartinm REST API")
+                               .description("Gustavo Martin Morcuende")
+                               .version("1.0-SNAPSHOT")
+                       .contact("gumartinm.name")
+                       .build();
+       }
+
+}
diff --git a/SpringJava/REST/web-services-spring-rest-global/src/doc/main/resources/spring-configuration/spring-config.xml b/SpringJava/REST/web-services-spring-rest-global/src/doc/main/resources/spring-configuration/spring-config.xml
new file mode 100644 (file)
index 0000000..5ca5917
--- /dev/null
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:context="http://www.springframework.org/schema/context"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+        http://www.springframework.org/schema/beans/spring-beans.xsd
+        http://www.springframework.org/schema/context
+        http://www.springframework.org/schema/context/spring-context.xsd
+        http://www.springframework.org/schema/util
+        http://www.springframework.org/schema/util/spring-util.xsd">
+
+       <!--
+       
+       Local deployment URLs:
+       
+       Swagger:
+       http://localhost:8080/web-services-spring-rest/spring-rest/v2/api-docs?group=web-services-spring-rest
+       
+       Swagger-UI:
+       http://localhost:8080/web-services-spring-rest/swagger-ui.html
+       
+       -->
+
+    <bean class="de.spring.webservices.rest.doc.Swagger2Configuration"/>
+
+</beans>
diff --git a/SpringJava/REST/web-services-spring-rest-global/src/main/java/de/spring/webservices/domain/Car.java b/SpringJava/REST/web-services-spring-rest-global/src/main/java/de/spring/webservices/domain/Car.java
new file mode 100644 (file)
index 0000000..cdfaa07
--- /dev/null
@@ -0,0 +1,58 @@
+package de.spring.webservices.domain;
+
+public class Car {
+
+    private final Long id;
+    private final String content;
+
+    // Required by Jackson :/
+    public Car() {
+       this.id = null;
+       this.content = null;
+    }
+    
+    public Car(Long id, String content) {
+        this.id = id;
+        this.content = content;
+    }
+
+    
+       public Long getId() {
+        return id;
+    }
+
+    public String getContent() {
+        return content;
+    }
+    
+    @Override
+       public int hashCode() {
+               final int prime = 31;
+               int result = 1;
+               result = prime * result + ((content == null) ? 0 : content.hashCode());
+               result = prime * result + ((id == null) ? 0 : id.hashCode());
+               return result;
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (this == obj)
+                       return true;
+               if (obj == null)
+                       return false;
+               if (getClass() != obj.getClass())
+                       return false;
+               Car other = (Car) obj;
+               if (content == null) {
+                       if (other.content != null)
+                               return false;
+               } else if (!content.equals(other.content))
+                       return false;
+               if (id == null) {
+                       if (other.id != null)
+                               return false;
+               } else if (!id.equals(other.id))
+                       return false;
+               return true;
+       }
+}
diff --git a/SpringJava/REST/web-services-spring-rest-server/pom.xml b/SpringJava/REST/web-services-spring-rest-server/pom.xml
new file mode 100644 (file)
index 0000000..cff3af6
--- /dev/null
@@ -0,0 +1,110 @@
+<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/maven-v4_0_0.xsd">
+       <modelVersion>4.0.0</modelVersion>
+       <parent>
+               <artifactId>web-services-spring-rest</artifactId>
+               <groupId>de.spring.webservices</groupId>
+               <version>1.0-SNAPSHOT</version>
+       </parent>
+       <artifactId>web-services-spring-rest-server</artifactId>
+       <packaging>war</packaging>
+       <name>web-services-spring-rest-server</name>
+       <url>http://gumartinm.name</url>
+       <dependencies>
+               <dependency>
+                       <groupId>de.spring.webservices</groupId>
+                       <artifactId>web-services-spring-rest-global</artifactId>
+                       <version>1.0-SNAPSHOT</version>
+               </dependency>
+               
+               <dependency>
+                       <groupId>org.springframework</groupId>
+                       <artifactId>spring-core</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.springframework</groupId>
+                       <artifactId>spring-webmvc</artifactId>
+               </dependency>
+               
+               <!-- Required by spring-webmvc -->
+               <dependency>
+                       <groupId>javax.servlet</groupId>
+                       <artifactId>javax.servlet-api</artifactId>
+                       <scope>provided</scope>
+               </dependency>
+               
+               <!-- Jackson JSON Processor, required by spring-webmvc. See messageConverters in rest-config.xml -->
+               <dependency>
+                       <groupId>com.fasterxml.jackson.core</groupId>
+                       <artifactId>jackson-databind</artifactId>
+               </dependency>
+               
+               <!-- Required by spring-context for using JSR-303. See LocalValidatorFactoryBean in rest-config.xml -->
+               <dependency>
+                       <groupId>javax.validation</groupId>
+                       <artifactId>validation-api</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.hibernate</groupId>
+                       <artifactId>hibernate-validator</artifactId>
+               </dependency>
+               
+               <!-- Unitary and integration tests -->
+               <dependency>
+                       <groupId>junit</groupId>
+                       <artifactId>junit</artifactId>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.springframework</groupId>
+                       <artifactId>spring-test</artifactId>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.mockito</groupId>
+                       <artifactId>mockito-core</artifactId>
+                       <scope>test</scope>
+               </dependency>
+               
+               <!-- Required by MockMvcResultMatchers (spring-test framework) -->
+               <dependency>
+                       <groupId>org.hamcrest</groupId>
+                       <artifactId>hamcrest-core</artifactId>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.hamcrest</groupId>
+                       <artifactId>hamcrest-library</artifactId>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
+                       <groupId>com.jayway.jsonpath</groupId>
+                       <artifactId>json-path</artifactId>
+                       <scope>test</scope>
+               </dependency>
+       </dependencies>
+       <build>
+               <finalName>${project.artifactId}</finalName>
+               <resources>
+                       <resource>
+                               <directory>${basedir}/src/main/webapp</directory>
+                               <excludes>
+                                       <exclude>**/*.*</exclude>
+                               </excludes>
+                       </resource>
+                       <resource>
+                               <directory>${basedir}/src/main/resources/</directory>
+                               <includes>
+                                       <include>**/*.*</include>
+                               </includes>
+                       </resource>
+               </resources>
+               
+               <plugins>
+                       <plugin>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-war-plugin</artifactId>
+                       </plugin>
+               </plugins>
+       </build>
+</project>
diff --git a/SpringJava/REST/web-services-spring-rest-server/src/doc/main/java/de/spring/webservices/rest/doc/Swagger2Configuration.java b/SpringJava/REST/web-services-spring-rest-server/src/doc/main/java/de/spring/webservices/rest/doc/Swagger2Configuration.java
new file mode 100644 (file)
index 0000000..6e0de24
--- /dev/null
@@ -0,0 +1,52 @@
+package de.spring.webservices.rest.doc;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger.web.UiConfiguration;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+@Configuration
+@EnableWebMvc
+@EnableSwagger2
+public class Swagger2Configuration {
+       private static final String DOCKET_ID = "web-services-spring-rest";
+       
+       @Bean
+       public Docket documentation() {
+               return new Docket(DocumentationType.SWAGGER_2)
+                               .groupName(DOCKET_ID)
+                               .select()
+                                       .apis(RequestHandlerSelectors.withMethodAnnotation(RequestMapping.class))
+                                       .paths(PathSelectors.any())
+                                       .build()
+                       .pathMapping("/")
+                       .useDefaultResponseMessages(false)
+                       .apiInfo(metadata())
+                       .enable(true);
+       }
+
+       @Bean
+       UiConfiguration uiConfig() {
+               return UiConfiguration.DEFAULT;
+       }
+
+       
+       private static ApiInfo metadata() {
+               return new ApiInfoBuilder()
+                               .title("gumartinm REST API")
+                               .description("Gustavo Martin Morcuende")
+                               .version("1.0-SNAPSHOT")
+                       .contact("gumartinm.name")
+                       .build();
+       }
+
+}
diff --git a/SpringJava/REST/web-services-spring-rest-server/src/doc/main/resources/spring-configuration/spring-config.xml b/SpringJava/REST/web-services-spring-rest-server/src/doc/main/resources/spring-configuration/spring-config.xml
new file mode 100644 (file)
index 0000000..5ca5917
--- /dev/null
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:context="http://www.springframework.org/schema/context"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+        http://www.springframework.org/schema/beans/spring-beans.xsd
+        http://www.springframework.org/schema/context
+        http://www.springframework.org/schema/context/spring-context.xsd
+        http://www.springframework.org/schema/util
+        http://www.springframework.org/schema/util/spring-util.xsd">
+
+       <!--
+       
+       Local deployment URLs:
+       
+       Swagger:
+       http://localhost:8080/web-services-spring-rest/spring-rest/v2/api-docs?group=web-services-spring-rest
+       
+       Swagger-UI:
+       http://localhost:8080/web-services-spring-rest/swagger-ui.html
+       
+       -->
+
+    <bean class="de.spring.webservices.rest.doc.Swagger2Configuration"/>
+
+</beans>
diff --git a/SpringJava/REST/web-services-spring-rest-server/src/main/java/de/spring/webservices/rest/CarController.java b/SpringJava/REST/web-services-spring-rest-server/src/main/java/de/spring/webservices/rest/CarController.java
new file mode 100644 (file)
index 0000000..b5ae241
--- /dev/null
@@ -0,0 +1,111 @@
+package de.spring.webservices.rest;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+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.RequestHeader;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
+
+import de.spring.webservices.domain.Car;
+
+//import io.swagger.annotations.ApiOperation;
+//import io.swagger.annotations.ApiResponse;
+//import io.swagger.annotations.ApiResponses;
+
+@RestController
+@RequestMapping("/api/cars/")
+public class CarController {
+       private static final Logger LOGGER = LoggerFactory.getLogger(CarController.class);
+    private static final String TEMPLATE = "Car: %s";
+    
+    private final AtomicLong counter = new AtomicLong();
+
+//  Do I want to release with Swagger dependencies?
+//    @ApiOperation(value = "getCars", nickname = "getAllCars", response = Car.class)
+//    @ApiResponses({
+//        @ApiResponse(code =  404, message ="Not found"),
+//        @ApiResponse(code =  400, message ="Invalid input")
+//    })
+    @RequestMapping(produces = { MediaType.APPLICATION_JSON_UTF8_VALUE }, method = RequestMethod.GET)
+    @ResponseStatus(HttpStatus.OK)
+    public List<Car> cars() {
+        final List<Car> cars = new ArrayList<>();
+        cars.add(new Car(counter.incrementAndGet(), String.format(TEMPLATE, 1)));
+        cars.add(new Car(counter.incrementAndGet(), String.format(TEMPLATE, 2)));
+        cars.add(new Car(counter.incrementAndGet(), String.format(TEMPLATE, 3)));
+
+        return cars;
+    }
+
+//  Do I want to release with Swagger dependencies?
+//  @ApiOperation(value = "getCar", nickname = "getsOneCar", response = Car.class)
+//  @ApiResponses({
+//      @ApiResponse(code =  404, message ="Not found"),
+//      @ApiResponse(code =  400, message ="Invalid input")
+//  })
+    @RequestMapping(value = "{id}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.GET)
+    @ResponseStatus(HttpStatus.OK)
+    public Car car(@RequestHeader(value = "MY_HEADER", required = false) String specialHeader,
+               @PathVariable("id") long id,
+               @RequestParam Map<String, String> params,
+               @RequestParam(value = "wheel", required = false) String[] wheelParams) {
+               
+       if (specialHeader != null) {
+               LOGGER.info("SPECIAL HEADER: " + specialHeader);
+       }
+        
+       if (params.get("mirror") != null) {
+               LOGGER.info("MIRROR: " + params.get("mirror")); 
+       }
+       
+       if (params.get("window") != null) {
+               LOGGER.info("WINDOW: " + params.get("window"));
+       }
+       
+       if (wheelParams != null) {
+               for(String wheel : wheelParams) {
+                       LOGGER.info(wheel);
+               }
+       }
+       
+        try {
+            Thread.sleep(10000);                 //1000 milliseconds is one second.
+        } catch(InterruptedException ex) {
+            Thread.currentThread().interrupt();
+        }
+
+
+        return new Car(counter.incrementAndGet(), String.format(TEMPLATE, id));
+    }
+    
+//  Do I want to release with Swagger dependencies?
+//  @ApiOperation(value = "postCat", nickname = "createsNewCar", response = Car.class)
+//  @ApiResponses({
+//      @ApiResponse(code =  404, message ="Not found"),
+//      @ApiResponse(code =  400, message ="Invalid input")
+//  })
+    @RequestMapping(consumes = MediaType.APPLICATION_JSON_UTF8_VALUE,
+               produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.POST)
+    public ResponseEntity<Car> create(@RequestBody Car car) {
+       long count = counter.incrementAndGet();
+       HttpHeaders headers = new HttpHeaders();
+       headers.add(HttpHeaders.LOCATION, "/api/cars/" + count);
+       
+        return new ResponseEntity<>(new Car(count, String.format(TEMPLATE, count)), headers, HttpStatus.CREATED);
+    }
+
+}
diff --git a/SpringJava/REST/web-services-spring-rest-server/src/main/resources/log4j2.xml b/SpringJava/REST/web-services-spring-rest-server/src/main/resources/log4j2.xml
new file mode 100644 (file)
index 0000000..ee36b97
--- /dev/null
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- 
+       status: The level of internal Log4j events that should be logged to the console.
+       Valid values for this attribute are "trace", "debug", "info", "warn", "error" and "fatal".
+       
+       monitorInterval: The minimum amount of time, in seconds, that must elapse before the file configuration is checked for changes.
+       
+       
+       see https://logging.apache.org/log4j/2.x/manual/configuration.html
+ -->
+<Configuration status="error" strict="true" monitorInterval="30"
+                name="XMLConfigTest" packages="org.apache.logging.log4j.test">
+                
+       <!--
+               ALL > TRACE > DEBUG > INFO > WARN > ERROR > OFF
+               
+               ERROR by default.
+       -->
+                
+    <Appenders>
+        <Appender type="Console" name="STDOUT">
+            <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
+        </Appender>
+    </Appenders>
+    <Loggers>
+    
+        <!-- 
+               Specific log level for Spring WEBMVC.
+        -->
+        <Logger name="org.springframework.web" level="INFO" additivity="false">
+            <AppenderRef ref="STDOUT" />
+        </Logger>
+    
+    
+               <!-- 
+               General logging Spring.
+        -->
+        <Logger name="org.springframework" level="INFO" additivity="false">
+            <AppenderRef ref="STDOUT" />
+        </Logger>
+    
+
+               <!-- 
+                       Anything else will be using TRACE logging level.
+                -->        
+        <Root level="INFO">
+            <AppenderRef ref="STDOUT"/>
+        </Root>
+        
+    </Loggers>
+</Configuration>
diff --git a/SpringJava/REST/web-services-spring-rest-server/src/main/resources/spring-configuration/mvc/rest/rest-config.xml b/SpringJava/REST/web-services-spring-rest-server/src/main/resources/spring-configuration/mvc/rest/rest-config.xml
new file mode 100644 (file)
index 0000000..bed7947
--- /dev/null
@@ -0,0 +1,72 @@
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:mvc="http://www.springframework.org/schema/mvc"
+       xmlns:context="http://www.springframework.org/schema/context"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xmlns:p="http://www.springframework.org/schema/p"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
+        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
+        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
+   
+       <!--
+               I am declaring my beans without the automatic annotation. :/
+               Better because we are saving memory but it requires more configuration.
+               
+               See: org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser
+               <mvc:annotation-driven/>
+        -->
+        
+   
+       <context:annotation-config />
+   
+       <context:component-scan base-package="de.spring.webservices.rest"/>
+
+    <bean id="jsonObjectMapperFactory" class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean" p:indentOutput="true" p:failOnEmptyBeans="false">
+        <property name="featuresToDisable">
+            <array>
+                <util:constant static-field="com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES"/>
+                <util:constant static-field="com.fasterxml.jackson.databind.MapperFeature.DEFAULT_VIEW_INCLUSION"/>
+            </array>
+        </property>
+    </bean>
+
+    <util:list id="messageConverters">
+        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" p:objectMapper-ref="jsonObjectMapperFactory"/>
+        <bean class="org.springframework.http.converter.StringHttpMessageConverter" />
+    </util:list>
+
+
+       <bean name="handlerAdapter"
+               class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
+               <property name="webBindingInitializer">
+                       <bean
+                               class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
+                               <!-- It enables us to use JSR-303 -->
+                               <property name="validator">
+                                       <bean class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
+                               </property>
+                       </bean>
+               </property>
+               <property name="messageConverters" ref="messageConverters" />
+               
+               
+               <property name="requestBodyAdvice">
+                       <util:list>
+                               <bean id="requestBodyAdvice" class="org.springframework.web.servlet.mvc.method.annotation.JsonViewRequestBodyAdvice"/>
+                       </util:list>
+               </property>
+               
+               
+               <property name="responseBodyAdvice">
+                       <util:list>
+                               <bean id="responseBodyAdvice" class="org.springframework.web.servlet.mvc.method.annotation.JsonViewResponseBodyAdvice"/>
+                       </util:list>
+               </property>
+       </bean>
+    
+       <bean id="handlerMapping" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
+
+       <mvc:default-servlet-handler />
+       
+</beans>
diff --git a/SpringJava/REST/web-services-spring-rest-server/src/main/resources/spring-configuration/spring-config.xml b/SpringJava/REST/web-services-spring-rest-server/src/main/resources/spring-configuration/spring-config.xml
new file mode 100644 (file)
index 0000000..e50129b
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:context="http://www.springframework.org/schema/context"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+        http://www.springframework.org/schema/beans/spring-beans.xsd
+        http://www.springframework.org/schema/context
+        http://www.springframework.org/schema/context/spring-context.xsd
+        http://www.springframework.org/schema/util
+        http://www.springframework.org/schema/util/spring-util.xsd">
+               
+</beans>
diff --git a/SpringJava/REST/web-services-spring-rest-server/src/main/webapp/WEB-INF/web.xml b/SpringJava/REST/web-services-spring-rest-server/src/main/webapp/WEB-INF/web.xml
new file mode 100644 (file)
index 0000000..26089bd
--- /dev/null
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
+         version="2.4">
+
+    <display-name>Spring REST Services: example</display-name>
+
+    <listener>
+        <listener-class>
+            org.springframework.web.context.ContextLoaderListener
+        </listener-class>
+    </listener>
+
+    <context-param>
+        <param-name>spring.profiles.active</param-name>
+        <param-value>${environment.profile}</param-value>
+        <param-name>contextConfigLocation</param-name>
+        <param-value>
+            classpath*:spring-configuration/*.xml
+        </param-value>
+    </context-param>
+    
+    <!-- Spring REST support -->
+    <servlet>
+        <servlet-name>spring-rest</servlet-name>
+        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
+        <load-on-startup>1</load-on-startup>
+        <async-supported>true</async-supported>
+        <init-param>
+           <param-name>contextConfigLocation</param-name>
+           <param-value>classpath*:spring-configuration/mvc/rest/*.xml</param-value>
+        </init-param>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>spring-rest</servlet-name>
+        <url-pattern>/spring-rest/*</url-pattern>
+    </servlet-mapping>
+
+</web-app>
diff --git a/SpringJava/REST/web-services-spring-rest-server/src/test/java/de/spring/webservices/rest/CarControllerIntegrationTest.java b/SpringJava/REST/web-services-spring-rest-server/src/test/java/de/spring/webservices/rest/CarControllerIntegrationTest.java
new file mode 100644 (file)
index 0000000..c551c85
--- /dev/null
@@ -0,0 +1,85 @@
+package de.spring.webservices.rest;
+
+import static org.hamcrest.Matchers.any;
+import static org.hamcrest.Matchers.is;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import de.spring.webservices.domain.Car;
+
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration({ "classpath*:spring-configuration/mvc/rest/*.xml"})
+public class CarControllerIntegrationTest {
+       private CarController controller;
+       private MockMvc mockMvc;
+       
+    @Before
+    public void setup() {
+       controller = new CarController();
+        mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
+    }
+
+       @Test
+       public void testWhenGetAllCarsThenRetrieveJsonValues() throws Exception {
+               mockMvc.perform(get("/api/cars/")
+                               .accept(MediaType.APPLICATION_JSON_UTF8))
+               
+               .andExpect(status().isOk())
+               .andExpect(jsonPath("$[0].id", any(Integer.class)))
+               .andExpect(jsonPath("$[0].content", is("Car: 1")))
+               .andExpect(jsonPath("$[1].content", is("Car: 2")))
+               .andExpect(jsonPath("$[1].id", any(Integer.class)))
+               .andExpect(jsonPath("$[2].content", is("Car: 3")))
+               .andExpect(jsonPath("$[2].id", any(Integer.class)))
+               .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8));
+       }
+       
+       @Test
+       public void testWhenGetOneCarThenRetrieveJsonValue() throws Exception {
+               mockMvc.perform(get("/api/cars/{id}", 1L)
+                               .accept(MediaType.APPLICATION_JSON_UTF8))
+       
+               .andExpect(status().isOk())
+               .andExpect(jsonPath("id", any(Integer.class)))
+               .andExpect(jsonPath("content", is("Car: 1")))
+               .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8));
+       }
+       
+       @Test
+       public void testWhenCreateNewCarThenRetrieveJsonValue() throws Exception {
+               Car car = new Car(2L, "nothing");
+               mockMvc.perform(post("/api/cars/")
+                               .contentType(MediaType.APPLICATION_JSON_UTF8)
+                               .content(asJsonString(car))
+                               .accept(MediaType.APPLICATION_JSON_UTF8))
+               
+               .andExpect(status().isCreated())
+               .andExpect(jsonPath("id", any(Integer.class)))
+               .andExpect(jsonPath("content", is("Car: 1")))
+               .andExpect(header().string(HttpHeaders.LOCATION, "/api/cars/1"))
+               .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8));
+       }
+       
+       private static String asJsonString(final Object obj) throws JsonProcessingException {
+               final ObjectMapper mapper = new ObjectMapper();
+               return mapper.writeValueAsString(obj);
+       }
+}
diff --git a/SpringJava/REST/web-services-spring-rest/pom.xml b/SpringJava/REST/web-services-spring-rest/pom.xml
new file mode 100644 (file)
index 0000000..bbad4e9
--- /dev/null
@@ -0,0 +1,317 @@
+<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/maven-v4_0_0.xsd">
+       <modelVersion>4.0.0</modelVersion>
+       <groupId>de.spring.webservices</groupId>
+       <artifactId>web-services-spring-rest</artifactId>
+       <packaging>pom</packaging>
+       <version>1.0-SNAPSHOT</version>
+       <name>web-services-spring-rest</name>
+       <url>http://gumartinm.name</url>
+       <description>Web Services Spring Framework</description>
+       <organization>
+               <name>Gustavo Martin Morcuende</name>
+               <url>http://www.gumartinm.name</url>
+       </organization>
+       <scm>
+               <developerConnection>scm:git:http://git.gumartinm.name/SpringWebServicesForFun</developerConnection>
+               <url>http://git.gumartinm.name/SpringWebServicesForFun</url>
+       </scm>
+       <properties>
+               <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+               <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+               <spring.version>4.2.4.RELEASE</spring.version>
+       </properties>
+       <profiles>
+               <profile>
+                       <id>release</id>
+                       <properties>
+                               <environment.profile>release</environment.profile>
+                       </properties>
+                       <activation>
+                               <activeByDefault>true</activeByDefault>
+                       </activation>
+               </profile>
+               <profile>
+                       <id>documentation</id>
+                       <properties>
+                               <environment.profile>documentation</environment.profile>
+                       </properties>
+                       <activation>
+                               <activeByDefault>false</activeByDefault>
+                       </activation>
+                       <dependencies>
+                               <!-- API documentation -->
+                               <dependency>
+                                       <groupId>io.springfox</groupId>
+                                       <artifactId>springfox-swagger2</artifactId>
+                                       <version>2.3.1</version>
+                               </dependency>
+                               <dependency>
+                                       <groupId>io.springfox</groupId>
+                                       <artifactId>springfox-swagger-ui</artifactId>
+                                       <version>2.3.1</version>
+                               </dependency>
+                       </dependencies>
+                       <build>
+                               <resources>
+                                       <resource>
+                                               <directory>${basedir}/src/doc/main/resources/</directory>
+                                               <includes>
+                                                       <include>**/*.*</include>
+                                               </includes>
+                                       </resource>
+                               </resources>
+                               <plugins>
+                                       <plugin>
+                                               <groupId>org.codehaus.mojo</groupId>
+                                               <artifactId>build-helper-maven-plugin</artifactId>
+                                               <version>1.10</version>
+                                               <executions>
+                                                       <execution>
+                                                               <id>add-source</id>
+                                                               <phase>process-sources</phase>
+                                                               <goals>
+                                                                       <goal>add-source</goal>
+                                                               </goals>
+                                                               <configuration>
+                                                                       <sources>
+                                                                               <source>src/doc/main/java/</source>
+                                                                       </sources>
+                                                               </configuration>
+                                                       </execution>
+                                               </executions>
+                                       </plugin>
+                               </plugins>
+                       </build>
+               </profile>
+       </profiles>
+       <dependencies>
+               <!-- 1/3 Required dependency for log4j 2 with slf4j: binding between log4j 
+                       2 and slf4j -->
+               <dependency>
+                       <groupId>org.apache.logging.log4j</groupId>
+                       <artifactId>log4j-slf4j-impl</artifactId>
+                       <version>2.3</version>
+               </dependency>
+               
+               <!-- 2/3 Required dependency for log4j 2 with slf4j: log4j 2 maven plugin 
+                       (it is the log4j 2 implementation) -->
+               <dependency>
+                       <groupId>org.apache.logging.log4j</groupId>
+                       <artifactId>log4j-core</artifactId>
+                       <version>2.3</version>
+               </dependency>
+               
+               <!-- 3/3 Required dependency for getting rid of commons logging. This is 
+                       the BRIDGE (no binding) between Jakarta Commons Logging (used by Spring) 
+                       and whatever I am using for logging (in this case I am using log4j 2) See: 
+                       http://www.slf4j.org/legacy.html We need exclusions in every dependency using 
+                       Jakarta Commons Logging (see Spring dependencies below) -->
+               <dependency>
+                       <groupId>org.slf4j</groupId>
+                       <artifactId>jcl-over-slf4j</artifactId>
+                       <version>1.7.12</version>
+               </dependency>
+               
+               
+               <dependency>
+                       <groupId>cglib</groupId>
+                       <artifactId>cglib</artifactId>
+                       <version>2.2.2</version>
+               </dependency>
+       </dependencies>
+       <dependencyManagement>
+               <dependencies>
+                       <dependency>
+                               <groupId>org.springframework</groupId>
+                               <artifactId>spring-core</artifactId>
+                               <version>${spring.version}</version>
+                               <!-- Required dependency for getting rid of commons logging and use my 
+                                       own logging library (in my case I decided to use log4j 2 under slf4j) -->
+                               <exclusions>
+                                       <exclusion>
+                                               <groupId>commons-logging</groupId>
+                                               <artifactId>commons-logging</artifactId>
+                                       </exclusion>
+                               </exclusions>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.springframework</groupId>
+                               <artifactId>spring-webmvc</artifactId>
+                               <version>${spring.version}</version>
+                               <!-- Required dependency for getting rid of commons logging and use my 
+                                       own logging library (in my case I decided to use log4j 2 under slf4j) -->
+                               <exclusions>
+                                       <exclusion>
+                                               <groupId>commons-logging</groupId>
+                                               <artifactId>commons-logging</artifactId>
+                                       </exclusion>
+                               </exclusions>
+                       </dependency>
+                       
+                       <!-- Required by spring-webmvc -->
+                       <dependency>
+                               <groupId>javax.servlet</groupId>
+                               <artifactId>javax.servlet-api</artifactId>
+                               <version>4.0.0-b01</version>
+                               <scope>provided</scope>
+                       </dependency>
+                       
+                       <!-- Jackson JSON Processor, required by spring-webmvc. See messageConverters 
+                               in rest-config.xml -->
+                       <dependency>
+                               <groupId>com.fasterxml.jackson.core</groupId>
+                               <artifactId>jackson-databind</artifactId>
+                               <version>2.6.4</version>
+                       </dependency>
+                       
+                       <!-- Required by spring-context for using JSR-303. See LocalValidatorFactoryBean 
+                               in rest-config.xml -->
+                       <dependency>
+                               <groupId>javax.validation</groupId>
+                               <artifactId>validation-api</artifactId>
+                               <version>1.1.0.Final</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.hibernate</groupId>
+                               <artifactId>hibernate-validator</artifactId>
+                               <version>5.2.2.Final</version>
+                       </dependency>
+                       
+                       <!-- Unitary and integration tests -->
+                       <dependency>
+                               <groupId>junit</groupId>
+                               <artifactId>junit</artifactId>
+                               <version>4.12</version>
+                               <scope>test</scope>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.springframework</groupId>
+                               <artifactId>spring-test</artifactId>
+                               <version>${spring.version}</version>
+                               <scope>test</scope>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.mockito</groupId>
+                               <artifactId>mockito-core</artifactId>
+                               <version>2.0.11-beta</version>
+                               <scope>test</scope>
+                       </dependency>
+                       
+                       <!-- Required by MockMvcResultMatchers (spring-test framework) -->
+                       <dependency>
+                               <groupId>org.hamcrest</groupId>
+                               <artifactId>hamcrest-core</artifactId>
+                               <version>1.3</version>
+                               <scope>test</scope>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.hamcrest</groupId>
+                               <artifactId>hamcrest-library</artifactId>
+                               <version>1.3</version>
+                               <scope>test</scope>
+                       </dependency>
+                       <dependency>
+                               <groupId>com.jayway.jsonpath</groupId>
+                               <artifactId>json-path</artifactId>
+                               <version>2.1.0</version>
+                               <scope>test</scope>
+                       </dependency>
+               </dependencies>
+       </dependencyManagement>
+       <build>
+               <pluginManagement>
+                       <plugins>
+                               <plugin>
+                                       <groupId>org.apache.maven.plugins</groupId>
+                                       <artifactId>maven-surefire-plugin</artifactId>
+                                       <version>2.18.1</version>
+                               </plugin>
+                               <plugin>
+                                       <groupId>org.apache.maven.plugins</groupId>
+                                       <artifactId>maven-failsafe-plugin</artifactId>
+                                       <version>2.18.1</version>
+                               </plugin>
+                               <plugin>
+                                       <groupId>org.apache.maven.plugins</groupId>
+                                       <artifactId>maven-war-plugin</artifactId>
+                                       <version>2.6</version>
+                                       <configuration>
+                                               <webResources>
+                                                       <resource>
+                                                               <filtering>true</filtering>
+                                                               <directory>src/main/webapp</directory>
+                                                               <includes>
+                                                                       <include>WEB-INF/web.xml</include>
+                                                               </includes>
+                                                       </resource>
+                                               </webResources>
+                                       </configuration>
+                               </plugin>
+                       </plugins>
+               </pluginManagement>
+               <plugins>
+                       <plugin>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-compiler-plugin</artifactId>
+                               <version>3.3</version>
+                               <configuration>
+                                       <source>1.8</source>
+                                       <target>1.8</target>
+                                       <encoding>${project.build.sourceEncoding}</encoding>
+                               </configuration>
+                       </plugin>
+                       <plugin>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-resources-plugin</artifactId>
+                               <version>2.7</version>
+                               <configuration>
+                                       <encoding>${project.build.sourceEncoding}</encoding>
+                               </configuration>
+                       </plugin>
+                       <plugin>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-jar-plugin</artifactId>
+                               <version>2.4</version>
+                               <configuration>
+                                       <archive>
+                                               <manifestEntries>
+                                                       <Specification-Title>${project.description}</Specification-Title>
+                                                       <Specification-Version>${project.version}</Specification-Version>
+                                                       <Specification-Vendor>${project.organization.name}</Specification-Vendor>
+                                                       <Implementation-Title>${project.description}</Implementation-Title>
+                                                       <Implementation-Version>${project.version}</Implementation-Version>
+                                                       <Implementation-Vendor>${project.organization.name}</Implementation-Vendor>
+                                               </manifestEntries>
+                                       </archive>
+                               </configuration>
+                       </plugin>
+                       <plugin>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-surefire-plugin</artifactId>
+                               <configuration>
+                                       <excludes>
+                                               <exclude>**/*IntegrationTest.java</exclude>
+                                       </excludes>
+                               </configuration>
+                       </plugin>
+                       <plugin>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-failsafe-plugin</artifactId>
+                               <executions>
+                                       <execution>
+                                               <goals>
+                                                       <goal>integration-test</goal>
+                                                       <goal>verify</goal>
+                                               </goals>
+                                       </execution>
+                               </executions>
+                               <configuration>
+                                       <includes>
+                                               <include>**/*IntegrationTest.java</include>
+                                       </includes>
+                               </configuration>
+                       </plugin>
+               </plugins>
+       </build>
+</project>
\ No newline at end of file