Spring Boot REST
authorGustavo Martin Morcuende <gu.martinm@gmail.com>
Sun, 5 Feb 2017 17:33:44 +0000 (18:33 +0100)
committerGustavo Martin Morcuende <gustavo.martin@scmspain.com>
Sun, 5 Feb 2017 20:08:14 +0000 (21:08 +0100)
79 files changed:
REST/Spring/web-services-spring-rest-client/pom.xml [new file with mode: 0644]
REST/Spring/web-services-spring-rest-client/src/main/java/de/spring/webservices/main/MainTest.java [new file with mode: 0644]
REST/Spring/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/business/service/BusinessService.java [new file with mode: 0644]
REST/Spring/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/business/service/impl/BusinessServiceImpl.java [new file with mode: 0644]
REST/Spring/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/client/service/CarClientService.java [new file with mode: 0644]
REST/Spring/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/client/service/impl/CarClientServiceImpl.java [new file with mode: 0644]
REST/Spring/web-services-spring-rest-client/src/main/resources/log4j2.xml [new file with mode: 0644]
REST/Spring/web-services-spring-rest-client/src/main/resources/rest.properties [new file with mode: 0644]
REST/Spring/web-services-spring-rest-client/src/main/resources/spring-configuration/rest-config.xml [new file with mode: 0644]
REST/Spring/web-services-spring-rest-client/src/test/java/de/spring/webservices/rest/business/service/BusinessServiceTest.java [new file with mode: 0644]
REST/Spring/web-services-spring-rest-client/src/test/java/de/spring/webservices/rest/client/service/CarClientServiceIntegrationTest.java [new file with mode: 0644]
REST/Spring/web-services-spring-rest-global/pom.xml [new file with mode: 0644]
REST/Spring/web-services-spring-rest-global/src/main/java/de/spring/webservices/domain/Car.java [new file with mode: 0644]
REST/Spring/web-services-spring-rest-server/pom.xml [new file with mode: 0644]
REST/Spring/web-services-spring-rest-server/src/main/java/de/spring/webservices/doc/Swagger2Configuration.java [new file with mode: 0644]
REST/Spring/web-services-spring-rest-server/src/main/java/de/spring/webservices/rest/controller/CarController.java [new file with mode: 0644]
REST/Spring/web-services-spring-rest-server/src/main/java/de/spring/webservices/rest/wadl/WADLController.java [new file with mode: 0644]
REST/Spring/web-services-spring-rest-server/src/main/resources/log4j2.xml [new file with mode: 0644]
REST/Spring/web-services-spring-rest-server/src/main/resources/spring-configuration/mvc/rest/rest-config.xml [new file with mode: 0644]
REST/Spring/web-services-spring-rest-server/src/main/resources/spring-configuration/spring-config.xml [new file with mode: 0644]
REST/Spring/web-services-spring-rest-server/src/main/resources/spring-configuration/spring-doc-config.xml [new file with mode: 0644]
REST/Spring/web-services-spring-rest-server/src/main/webapp/WEB-INF/web.xml [new file with mode: 0644]
REST/Spring/web-services-spring-rest-server/src/test/java/de/spring/webservices/rest/controller/CarControllerIntegrationTest.java [new file with mode: 0644]
REST/Spring/web-services-spring-rest/pom.xml [new file with mode: 0644]
REST/SpringBoot/pom.xml [new file with mode: 0644]
REST/SpringBoot/web-services-spring-rest-bom/pom.xml [new file with mode: 0644]
REST/SpringBoot/web-services-spring-rest-client/pom.xml [new file with mode: 0644]
REST/SpringBoot/web-services-spring-rest-client/src/main/java/de/spring/webservices/main/MainTest.java [new file with mode: 0644]
REST/SpringBoot/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/business/service/BusinessService.java [new file with mode: 0644]
REST/SpringBoot/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/business/service/impl/BusinessServiceImpl.java [new file with mode: 0644]
REST/SpringBoot/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/client/service/CarClientService.java [new file with mode: 0644]
REST/SpringBoot/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/client/service/impl/CarClientServiceImpl.java [new file with mode: 0644]
REST/SpringBoot/web-services-spring-rest-client/src/main/resources/log4j2.xml [new file with mode: 0644]
REST/SpringBoot/web-services-spring-rest-client/src/main/resources/rest.properties [new file with mode: 0644]
REST/SpringBoot/web-services-spring-rest-client/src/main/resources/spring-configuration/rest-config.xml [new file with mode: 0644]
REST/SpringBoot/web-services-spring-rest-client/src/test/java/de/spring/webservices/rest/business/service/BusinessServiceTest.java [new file with mode: 0644]
REST/SpringBoot/web-services-spring-rest-client/src/test/java/de/spring/webservices/rest/client/service/CarClientServiceIntegrationTest.java [new file with mode: 0644]
REST/SpringBoot/web-services-spring-rest-global/pom.xml [new file with mode: 0644]
REST/SpringBoot/web-services-spring-rest-global/src/main/java/de/spring/webservices/domain/Car.java [new file with mode: 0644]
REST/SpringBoot/web-services-spring-rest-server/logback-access.xml [new file with mode: 0644]
REST/SpringBoot/web-services-spring-rest-server/logback.xml [new file with mode: 0644]
REST/SpringBoot/web-services-spring-rest-server/pom.xml [new file with mode: 0644]
REST/SpringBoot/web-services-spring-rest-server/src/main/java/de/spring/webservices/Application.java [new file with mode: 0644]
REST/SpringBoot/web-services-spring-rest-server/src/main/java/de/spring/webservices/configuration/JacksonConfiguration.java [new file with mode: 0644]
REST/SpringBoot/web-services-spring-rest-server/src/main/java/de/spring/webservices/configuration/Swagger2Configuration.java [new file with mode: 0644]
REST/SpringBoot/web-services-spring-rest-server/src/main/java/de/spring/webservices/configuration/ValidatorConfiguration.java [new file with mode: 0644]
REST/SpringBoot/web-services-spring-rest-server/src/main/java/de/spring/webservices/configuration/WadlConfiguration.java [new file with mode: 0644]
REST/SpringBoot/web-services-spring-rest-server/src/main/java/de/spring/webservices/rest/controller/CarController.java [new file with mode: 0644]
REST/SpringBoot/web-services-spring-rest-server/src/main/java/de/spring/webservices/rest/wadl/WADLController.java [new file with mode: 0644]
REST/SpringBoot/web-services-spring-rest-server/src/main/resources/application.yml [new file with mode: 0644]
REST/SpringBoot/web-services-spring-rest-server/src/main/resources/banner.txt [new file with mode: 0644]
REST/SpringBoot/web-services-spring-rest-server/src/main/resources/log4j2.xml [new file with mode: 0644]
REST/SpringBoot/web-services-spring-rest-server/src/main/webapp/WEB-INF/web.xml [new file with mode: 0644]
REST/SpringBoot/web-services-spring-rest-server/src/test/java/de/spring/webservices/rest/controller/CarControllerIntegrationTest.java [new file with mode: 0644]
REST/SpringBoot/web-services-spring-rest-server/src/test/resources/application.yml [new file with mode: 0644]
REST/web-services-spring-rest-client/pom.xml [deleted file]
REST/web-services-spring-rest-client/src/main/java/de/spring/webservices/main/MainTest.java [deleted file]
REST/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/business/service/BusinessService.java [deleted file]
REST/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/business/service/impl/BusinessServiceImpl.java [deleted file]
REST/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/client/service/CarClientService.java [deleted file]
REST/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/client/service/impl/CarClientServiceImpl.java [deleted file]
REST/web-services-spring-rest-client/src/main/resources/log4j2.xml [deleted file]
REST/web-services-spring-rest-client/src/main/resources/rest.properties [deleted file]
REST/web-services-spring-rest-client/src/main/resources/spring-configuration/rest-config.xml [deleted file]
REST/web-services-spring-rest-client/src/test/java/de/spring/webservices/rest/business/service/BusinessServiceTest.java [deleted file]
REST/web-services-spring-rest-client/src/test/java/de/spring/webservices/rest/client/service/CarClientServiceIntegrationTest.java [deleted file]
REST/web-services-spring-rest-global/pom.xml [deleted file]
REST/web-services-spring-rest-global/src/main/java/de/spring/webservices/domain/Car.java [deleted file]
REST/web-services-spring-rest-server/pom.xml [deleted file]
REST/web-services-spring-rest-server/src/main/java/de/spring/webservices/doc/Swagger2Configuration.java [deleted file]
REST/web-services-spring-rest-server/src/main/java/de/spring/webservices/rest/controller/CarController.java [deleted file]
REST/web-services-spring-rest-server/src/main/java/de/spring/webservices/rest/wadl/WADLController.java [deleted file]
REST/web-services-spring-rest-server/src/main/resources/log4j2.xml [deleted file]
REST/web-services-spring-rest-server/src/main/resources/spring-configuration/mvc/rest/rest-config.xml [deleted file]
REST/web-services-spring-rest-server/src/main/resources/spring-configuration/spring-config.xml [deleted file]
REST/web-services-spring-rest-server/src/main/resources/spring-configuration/spring-doc-config.xml [deleted file]
REST/web-services-spring-rest-server/src/main/webapp/WEB-INF/web.xml [deleted file]
REST/web-services-spring-rest-server/src/test/java/de/spring/webservices/rest/controller/CarControllerIntegrationTest.java [deleted file]
REST/web-services-spring-rest/pom.xml [deleted file]

diff --git a/REST/Spring/web-services-spring-rest-client/pom.xml b/REST/Spring/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/REST/Spring/web-services-spring-rest-client/src/main/java/de/spring/webservices/main/MainTest.java b/REST/Spring/web-services-spring-rest-client/src/main/java/de/spring/webservices/main/MainTest.java
new file mode 100644 (file)
index 0000000..0f066ad
--- /dev/null
@@ -0,0 +1,35 @@
+package de.spring.webservices.main;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+import de.spring.webservices.rest.business.service.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/REST/Spring/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/business/service/BusinessService.java b/REST/Spring/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/business/service/BusinessService.java
new file mode 100644 (file)
index 0000000..ca7a7f2
--- /dev/null
@@ -0,0 +1,11 @@
+package de.spring.webservices.rest.business.service;
+
+
+public interface BusinessService {
+
+       public void doSomethingWithCars();
+       
+       public void doSomethingWithCar(long id);
+       
+       public void createsNewCar();
+}
diff --git a/REST/Spring/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/business/service/impl/BusinessServiceImpl.java b/REST/Spring/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/business/service/impl/BusinessServiceImpl.java
new file mode 100644 (file)
index 0000000..b6367e8
--- /dev/null
@@ -0,0 +1,53 @@
+package de.spring.webservices.rest.business.service.impl;
+
+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.business.service.BusinessService;
+import de.spring.webservices.rest.client.service.CarClientService;
+
+@Service("businessService")
+public class BusinessServiceImpl implements BusinessService {
+       private static final Logger LOGGER = LoggerFactory.getLogger(BusinessServiceImpl.class);
+
+       private final CarClientService carClientService;
+
+       @Autowired
+       public BusinessServiceImpl(CarClientService carClientService) {
+               this.carClientService = carClientService;
+       }
+       
+       
+       @Override
+       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());
+               }
+       }
+       
+       @Override
+       public void doSomethingWithCar(long id) {               
+               Car car = carClientService.doGetCar(id);
+               LOGGER.info("Retrieved car");
+               LOGGER.info("car: " + car.getId());
+               LOGGER.info(car.getContent());
+       }
+       
+       @Override
+       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/REST/Spring/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/client/service/CarClientService.java b/REST/Spring/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/client/service/CarClientService.java
new file mode 100644 (file)
index 0000000..23966ba
--- /dev/null
@@ -0,0 +1,14 @@
+package de.spring.webservices.rest.client.service;
+
+import java.util.List;
+
+import de.spring.webservices.domain.Car;
+
+public interface CarClientService {
+
+       public List<Car> doGetCars();
+       
+       public Car doGetCar(long id);
+       
+       public Car doNewCar(Car car);
+}
diff --git a/REST/Spring/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/client/service/impl/CarClientServiceImpl.java b/REST/Spring/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/client/service/impl/CarClientServiceImpl.java
new file mode 100644 (file)
index 0000000..bdb540b
--- /dev/null
@@ -0,0 +1,58 @@
+package de.spring.webservices.rest.client.service.impl;
+
+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;
+import de.spring.webservices.rest.client.service.CarClientService;
+
+@Service("carClientService")
+public class CarClientServiceImpl implements CarClientService {
+       private static final Logger LOGGER = LoggerFactory.getLogger(CarClientServiceImpl.class);
+
+       private final String apiCarsUrl;
+       private final String apiCarUrl;
+       private final RestTemplate restTemplate;
+       
+    @Autowired
+       public CarClientServiceImpl(@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;
+       }
+
+       
+    @Override
+       public List<Car> doGetCars() {                          
+               ResponseEntity<Car[]> responseEntity = restTemplate.getForEntity(apiCarsUrl, Car[].class);
+               
+               return Arrays.asList(responseEntity.getBody());
+       }
+       
+    @Override
+       public Car doGetCar(long id) {                          
+               ResponseEntity<Car> responseEntity = restTemplate.getForEntity(
+                               apiCarUrl.replace(":id", String.valueOf(id)), Car.class);
+               
+               return responseEntity.getBody();
+       }
+       
+    @Override
+       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/REST/Spring/web-services-spring-rest-client/src/main/resources/log4j2.xml b/REST/Spring/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/REST/Spring/web-services-spring-rest-client/src/main/resources/rest.properties b/REST/Spring/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/REST/Spring/web-services-spring-rest-client/src/main/resources/spring-configuration/rest-config.xml b/REST/Spring/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/REST/Spring/web-services-spring-rest-client/src/test/java/de/spring/webservices/rest/business/service/BusinessServiceTest.java b/REST/Spring/web-services-spring-rest-client/src/test/java/de/spring/webservices/rest/business/service/BusinessServiceTest.java
new file mode 100644 (file)
index 0000000..53665c4
--- /dev/null
@@ -0,0 +1,67 @@
+package de.spring.webservices.rest.business.service;
+
+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 org.mockito.ArgumentCaptor;
+
+import de.spring.webservices.domain.Car;
+import de.spring.webservices.rest.business.service.impl.BusinessServiceImpl;
+import de.spring.webservices.rest.client.service.CarClientService;
+
+public class BusinessServiceTest {
+
+       private CarClientService carClientService;
+       private BusinessService businessService;
+       
+    @Before
+    public void createTest() {
+       carClientService = mock(CarClientService.class);
+       businessService = new BusinessServiceImpl(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);
+       }
+       
+       @Test
+       public void whenCreateNewCarThenCreateNewOne() {
+               Car expected = new Car(66L, "test");
+               ArgumentCaptor<Car> argCar = ArgumentCaptor.forClass(Car.class);
+               
+               when(carClientService.doNewCar(argCar.capture())).thenReturn(expected);
+               
+               businessService.createsNewCar();
+               
+               verify(carClientService, times(1)).doNewCar(argCar.getValue());
+       }
+}
diff --git a/REST/Spring/web-services-spring-rest-client/src/test/java/de/spring/webservices/rest/client/service/CarClientServiceIntegrationTest.java b/REST/Spring/web-services-spring-rest-client/src/test/java/de/spring/webservices/rest/client/service/CarClientServiceIntegrationTest.java
new file mode 100644 (file)
index 0000000..b5696be
--- /dev/null
@@ -0,0 +1,117 @@
+package de.spring.webservices.rest.client.service;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.springframework.test.web.client.match.MockRestRequestMatchers.content;
+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.http.converter.json.Jackson2ObjectMapperFactoryBean;
+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 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;
+    
+    @Autowired
+    private Jackson2ObjectMapperFactoryBean jsonObjectMapperFactory;
+
+    private MockRestServiceServer mockServer;
+
+    @Before
+    public void createTest() {
+        mockServer = MockRestServiceServer.createServer(restTemplate);
+    }
+
+       @Test
+       public void whenGetAllCarsThenRetrieveRequestedCars() throws JsonProcessingException {
+               Car expectedOne = new Car(66L, "test");
+               List<Car> expected = new ArrayList<>();
+               expected.add(expectedOne);
+               
+               mockServer.expect(requestTo(apiCarsUrl))
+                                       .andExpect(method(HttpMethod.GET))
+                                       .andRespond(withSuccess(asJsonString(expected), MediaType.APPLICATION_JSON_UTF8));
+
+               List<Car> cars = carClientService.doGetCars();
+
+               mockServer.verify();
+               
+               assertEquals(1, cars.size());
+               assertEquals(expectedOne, cars.get(0));
+       }
+       
+       @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))
+                                       .andExpect(content()
+                                                       .string(asJsonString(expected)))
+                                       .andRespond(withSuccess(asJsonString(expected), MediaType.APPLICATION_JSON_UTF8)
+                                                       .headers(headers));
+
+               Car car = carClientService.doNewCar(expected);
+
+               mockServer.verify();
+               
+               assertNotNull(car);
+               assertEquals(expected, car);
+       }
+       
+       private String asJsonString(final Object obj) throws JsonProcessingException {
+               return jsonObjectMapperFactory.getObject().writeValueAsString(obj);
+       }
+}
diff --git a/REST/Spring/web-services-spring-rest-global/pom.xml b/REST/Spring/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/REST/Spring/web-services-spring-rest-global/src/main/java/de/spring/webservices/domain/Car.java b/REST/Spring/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/REST/Spring/web-services-spring-rest-server/pom.xml b/REST/Spring/web-services-spring-rest-server/pom.xml
new file mode 100644 (file)
index 0000000..144a67c
--- /dev/null
@@ -0,0 +1,139 @@
+<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>
+
+               <!-- Creates WADL from Spring REST annotations -->
+               <dependency>
+                       <groupId>org.jvnet.ws.wadl</groupId>
+                       <artifactId>wadl-core</artifactId>
+                       <version>1.1.6</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.jvnet.ws.wadl</groupId>
+                       <artifactId>wadl-client-plugin</artifactId>
+                       <version>1.1.6</version>
+               </dependency>
+               <dependency>
+               <groupId>org.springframework</groupId>
+               <artifactId>spring-oxm</artifactId>
+               <version>4.2.4.RELEASE</version>
+               </dependency>
+
+               <!-- API documentation -->
+               <dependency>
+                       <groupId>io.springfox</groupId>
+                       <artifactId>springfox-swagger1</artifactId>
+                       <version>2.3.1</version>
+               </dependency>
+               <dependency>
+                       <groupId>io.springfox</groupId>
+                       <artifactId>springfox-swagger-ui</artifactId>
+                       <version>2.3.1</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>
+               </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/REST/Spring/web-services-spring-rest-server/src/main/java/de/spring/webservices/doc/Swagger2Configuration.java b/REST/Spring/web-services-spring-rest-server/src/main/java/de/spring/webservices/doc/Swagger2Configuration.java
new file mode 100644 (file)
index 0000000..df71590
--- /dev/null
@@ -0,0 +1,58 @@
+package de.spring.webservices.doc;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+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.builders.ResponseMessageBuilder;
+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.swagger1.annotations.EnableSwagger;
+
+@Configuration
+@EnableWebMvc
+@EnableSwagger
+@ComponentScan("de.spring.webservices.rest.controller")
+public class Swagger2Configuration {
+       
+       @Bean
+       public Docket documentation() {
+               return new Docket(DocumentationType.SWAGGER_12)
+                               .select()
+                                       .apis(RequestHandlerSelectors.withMethodAnnotation(RequestMapping.class))
+                                       .paths(PathSelectors.any())
+                                       .build()
+                                       .globalResponseMessage(RequestMethod.GET,
+                                                       newArrayList(new ResponseMessageBuilder()
+                                                                       .code(500).message("Global server custom error message").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/REST/Spring/web-services-spring-rest-server/src/main/java/de/spring/webservices/rest/controller/CarController.java b/REST/Spring/web-services-spring-rest-server/src/main/java/de/spring/webservices/rest/controller/CarController.java
new file mode 100644 (file)
index 0000000..49acf64
--- /dev/null
@@ -0,0 +1,112 @@
+package de.spring.webservices.rest.controller;
+
+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.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import io.swagger.annotations.ResponseHeader;
+
+@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();
+
+       @ApiOperation(value = "Get all available cars", nickname = "getAllCars", responseContainer="List", response = Car.class)
+    @ApiResponses({
+        @ApiResponse(code =  404, message ="Specific getCars not found"),
+        @ApiResponse(code =  400, message ="Specific getCars 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;
+    }
+
+       @ApiOperation(value = "Get one car", nickname = "getOneCar", response = Car.class)
+    @ApiResponses({
+        @ApiResponse(code =  404, message ="Specific getCar not found"),
+        @ApiResponse(code =  400, message ="Specific getCar 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,
+               @ApiParam(name = "id", value = "Car id", required = true) @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));
+    }
+    
+       @ApiOperation(code =  201, value = "Create one new car", nickname = "createNewCar")
+    @ApiResponses({
+       @ApiResponse(code =  201, message ="Specific createCar with header",
+                       responseHeaders = { @ResponseHeader(name = HttpHeaders.LOCATION) }, response = Car.class),
+        @ApiResponse(code =  404, message ="Specific createCar not found"),
+        @ApiResponse(code =  400, message ="Specific createCar invalid input")
+    })
+    @RequestMapping(consumes = MediaType.APPLICATION_JSON_UTF8_VALUE,
+               produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.POST)
+       @ResponseStatus(HttpStatus.CREATED)
+    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/REST/Spring/web-services-spring-rest-server/src/main/java/de/spring/webservices/rest/wadl/WADLController.java b/REST/Spring/web-services-spring-rest-server/src/main/java/de/spring/webservices/rest/wadl/WADLController.java
new file mode 100644 (file)
index 0000000..1125157
--- /dev/null
@@ -0,0 +1,236 @@
+package de.spring.webservices.rest.wadl;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.xml.namespace.QName;
+
+import org.apache.commons.lang.StringUtils;
+import org.jvnet.ws.wadl.Application;
+import org.jvnet.ws.wadl.Doc;
+import org.jvnet.ws.wadl.Param;
+import org.jvnet.ws.wadl.ParamStyle;
+import org.jvnet.ws.wadl.Representation;
+import org.jvnet.ws.wadl.Request;
+import org.jvnet.ws.wadl.Resource;
+import org.jvnet.ws.wadl.Resources;
+import org.jvnet.ws.wadl.Response;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.ValueConstants;
+import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
+import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
+
+/**
+ * Taken from: http://javattitude.com/2014/05/26/wadl-generator-for-spring-rest/
+ * 
+ * With some modifications.
+ *
+ */
+@Controller
+@RequestMapping("/rest.wadl")
+public class WADLController {
+       private static final String NAMESPACE_URI = "http://www.w3.org/2001/XMLSchema" ;
+       private static final String WADL_TITLE = "Spring REST Service WADL";
+       
+    private final AbstractHandlerMethodMapping<RequestMappingInfo> handlerMapping;
+    private final ApplicationContext context;
+    
+    @Autowired
+       public WADLController(AbstractHandlerMethodMapping<RequestMappingInfo> handlerMapping, ApplicationContext context) {
+               this.handlerMapping = handlerMapping;
+               this.context = context;
+       }
+       
+    @RequestMapping(produces = { MediaType.APPLICATION_XML_VALUE }, method=RequestMethod.GET ) 
+    public @ResponseBody Application generateWadl(HttpServletRequest request) {
+        Application result = new Application();
+        
+        Doc doc = new Doc();
+        doc.setTitle(WADL_TITLE);
+        result.getDoc().add(doc);
+        
+        Resources wadlResources = new Resources();
+        wadlResources.setBase(getBaseUrl(request));
+                 
+        handlerMapping.getHandlerMethods().forEach( (mappingInfo, handlerMethod) -> {
+            Object object = handlerMethod.getBean();
+            Object bean = context.getBean(object.toString());
+            if(!bean.getClass().isAnnotationPresent(RestController.class)) {
+               return;
+            }
+            
+            mappingInfo.getMethodsCondition().getMethods().forEach(httpMethod -> {
+               Resource wadlResource = null; 
+                org.jvnet.ws.wadl.Method wadlMethod = new org.jvnet.ws.wadl.Method();
+     
+                Set<String> pattern =  mappingInfo.getPatternsCondition().getPatterns();
+                for (String uri : pattern) {
+                       wadlResource = createOrFind(uri, wadlResources); 
+                    wadlResource.setPath(uri);      
+                }
+                 
+                wadlMethod.setName(httpMethod.name());
+                Method javaMethod = handlerMethod.getMethod();
+                wadlMethod.setId(javaMethod.getName());
+                Doc wadlDocMethod = new Doc();
+                wadlDocMethod.setTitle(javaMethod.getDeclaringClass().getSimpleName() + "." + javaMethod.getName());
+                wadlMethod.getDoc().add(wadlDocMethod);
+                 
+                // Request
+                Request wadlRequest = new Request();
+                Annotation[][] annotations = javaMethod.getParameterAnnotations();
+                Class<?>[] paramTypes = javaMethod.getParameterTypes();
+                int i = 0;
+                for (Annotation[] annotation : annotations) {
+                       Class<?> paramType =paramTypes[i];
+                       i++;
+                    for (Annotation annotation2 : annotation) {
+                    
+                       Param wadlParam = doParam(annotation2, paramType);
+                       if (wadlParam != null) {
+                               wadlRequest.getParam().add(wadlParam);
+                       }
+                    }
+                }
+                if (!wadlRequest.getParam().isEmpty() ) {
+                    wadlMethod.setRequest(wadlRequest);
+                }
+                 
+                // Response
+                Set<MediaType> mediaTypes = mappingInfo.getProducesCondition().getProducibleMediaTypes();
+                if (!mediaTypes.isEmpty()) {
+                       ResponseStatus status = handlerMethod.getMethodAnnotation(ResponseStatus.class);
+                    Response wadlResponse = doResponse(mediaTypes, status);
+                    wadlMethod.getResponse().add(wadlResponse);
+                }
+                
+                
+                wadlResource.getMethodOrResource().add(wadlMethod);          
+            });
+             
+        });
+        result.getResources().add(wadlResources);
+         
+        return result;
+    }
+    
+    private Param doParam(Annotation annotation2, Class<?> paramType) {
+       Param wadlParam = null;
+       
+        if (annotation2 instanceof RequestParam ) {
+            RequestParam param = (RequestParam)annotation2;
+            
+            wadlParam = new Param();
+            QName nm = convertJavaToXMLType(paramType);
+            if (StringUtils.isNotEmpty(nm.getLocalPart())) {
+               wadlParam.setType(nm);
+            }
+            wadlParam.setName(param.value());
+            
+            
+            if (!ValueConstants.DEFAULT_NONE.equals(param.defaultValue())) {
+                String defaultValue = cleanDefault(param.defaultValue());
+                if (StringUtils.isNotEmpty(defaultValue) ) {
+                    wadlParam.setDefault(defaultValue);
+                }
+            }
+
+            wadlParam.setStyle(ParamStyle.QUERY);
+            wadlParam.setRequired(param.required());       
+        } else if (annotation2 instanceof PathVariable ) {
+            PathVariable param = (PathVariable)annotation2;
+            
+            wadlParam = new Param();                            
+            QName nm = convertJavaToXMLType(paramType);
+            if (StringUtils.isNotEmpty(nm.getLocalPart())) {
+               wadlParam.setType(nm);
+            }
+            wadlParam.setName(param.value());
+            
+            
+            wadlParam.setStyle(ParamStyle.TEMPLATE);
+            wadlParam.setRequired(true);
+        }
+        
+        return wadlParam;
+    }
+     
+    private Response doResponse(Set<MediaType> mediaTypes, ResponseStatus status) {
+       Response wadlResponse = new Response();
+        
+        mediaTypes.forEach(mediaType -> {
+            Representation wadlRepresentation = new Representation();
+            wadlRepresentation.setMediaType(mediaType.toString());
+            wadlResponse.getRepresentation().add(wadlRepresentation);
+        });
+        
+        wadlResponse.getStatus().add(getResposeValue(status));
+
+        return wadlResponse;
+    }
+    
+    private long getResposeValue(ResponseStatus status) {
+       if(status == null) {
+               return HttpStatus.OK.value();
+        } else {
+            HttpStatus httpcode = status.value();
+            return httpcode.value();
+        }
+    }
+    
+    private QName convertJavaToXMLType(Class<?> type) {
+       QName nm = new QName("");
+       String classname = type.toString();
+       classname = classname.toLowerCase();
+       
+               if (classname.indexOf("string") >= 0) {
+                       nm = new QName(NAMESPACE_URI, "string", "xs");
+               } else if (classname.indexOf("integer") >= 0) {
+                       nm = new QName(NAMESPACE_URI, "int", "xs");
+               } else if (classname.indexOf("long") >= 0) {
+                       nm = new QName(NAMESPACE_URI, "long", "xs");
+               }
+       
+       return nm;
+    }
+    
+    private Resource createOrFind(String uri, Resources wadResources) {
+         List<Resource> current = wadResources.getResource();
+         for(Resource resource:current) {
+                 if(resource.getPath().equalsIgnoreCase(uri)){
+                         return resource;
+                 }
+         }
+         Resource wadlResource = new Resource();
+         current.add(wadlResource);
+         return wadlResource;
+    }
+    
+    private String getBaseUrl(HttpServletRequest request) {
+        String requestUri = request.getRequestURI();
+        int index = requestUri.lastIndexOf('/');
+        requestUri = requestUri.substring(0, index);
+        
+        return request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + requestUri;
+    }
+     
+    private String cleanDefault(String value) {
+        value = value.replaceAll("\t", "");
+        value = value.replaceAll("\n", "");
+        return value;
+    }
+}
diff --git a/REST/Spring/web-services-spring-rest-server/src/main/resources/log4j2.xml b/REST/Spring/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/REST/Spring/web-services-spring-rest-server/src/main/resources/spring-configuration/mvc/rest/rest-config.xml b/REST/Spring/web-services-spring-rest-server/src/main/resources/spring-configuration/mvc/rest/rest-config.xml
new file mode 100644 (file)
index 0000000..54b8540
--- /dev/null
@@ -0,0 +1,88 @@
+<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"/>
+       
+       <!--
+               Required beans for generating XML responses from Java objects using JAXB annotations
+               Jackson also works but it doesn't generate XML with namespaces... O.o
+               
+               This implementation will be slower than the one using Jackson :( but I am going to use it just for WADL generation :)
+       -->    
+    <bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
+        <property name="packagesToScan" value="org.jvnet.ws.wadl"/>
+    </bean>
+       <bean id="jaxbConverter" class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
+       <constructor-arg ref="jaxbMarshaller" />
+       </bean>
+    
+       <!-- Required beans for generating JSON responses from Java objects -->
+    <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"/>
+               <ref bean="jaxbConverter" />
+        <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/REST/Spring/web-services-spring-rest-server/src/main/resources/spring-configuration/spring-config.xml b/REST/Spring/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/REST/Spring/web-services-spring-rest-server/src/main/resources/spring-configuration/spring-doc-config.xml b/REST/Spring/web-services-spring-rest-server/src/main/resources/spring-configuration/spring-doc-config.xml
new file mode 100644 (file)
index 0000000..773e14f
--- /dev/null
@@ -0,0 +1,31 @@
+<?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-server/api-docs
+       
+       Swagger-UI:
+       http://localhost:8080/web-services-spring-rest-server/swagger-ui.html
+       
+       -->
+
+       <context:annotation-config />
+   
+       <context:component-scan base-package="de.spring.webservices.doc"/>
+       
+    <bean class="de.spring.webservices.doc.Swagger2Configuration"/>
+
+</beans>
diff --git a/REST/Spring/web-services-spring-rest-server/src/main/webapp/WEB-INF/web.xml b/REST/Spring/web-services-spring-rest-server/src/main/webapp/WEB-INF/web.xml
new file mode 100644 (file)
index 0000000..6c9c1d0
--- /dev/null
@@ -0,0 +1,41 @@
+<?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>
+        <!-- REQUIRED PATTERN BY swagger-ui. IT DOESN'T WORK WITH ANY OTHER o.O -->
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+</web-app>
diff --git a/REST/Spring/web-services-spring-rest-server/src/test/java/de/spring/webservices/rest/controller/CarControllerIntegrationTest.java b/REST/Spring/web-services-spring-rest-server/src/test/java/de/spring/webservices/rest/controller/CarControllerIntegrationTest.java
new file mode 100644 (file)
index 0000000..c856efb
--- /dev/null
@@ -0,0 +1,85 @@
+package de.spring.webservices.rest.controller;
+
+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/REST/Spring/web-services-spring-rest/pom.xml b/REST/Spring/web-services-spring-rest/pom.xml
new file mode 100644 (file)
index 0000000..e8ce3dc
--- /dev/null
@@ -0,0 +1,265 @@
+<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>
+       </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
diff --git a/REST/SpringBoot/pom.xml b/REST/SpringBoot/pom.xml
new file mode 100644 (file)
index 0000000..9b7f623
--- /dev/null
@@ -0,0 +1,27 @@
+<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.example.spring.kafka</groupId>
+    <artifactId>web-services-spring-rest</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+    <name>web-services-spring-rest</name>
+    <url>https://gumartinm.name/</url>
+    <description>Web Services Spring REST</description>
+    <organization>
+        <name>gumartinm</name>
+        <url>https://gumartinm.name/</url>
+    </organization>
+    <scm>
+        <developerConnection>scm:git:https://git.gumartinm.name/SpringWebServicesForFun</developerConnection>
+        <url>https://git.gumartinm.name/SpringWebServicesForFun</url>
+    </scm>
+
+    <modules>
+        <module>web-services-spring-rest-bom</module>
+        <module>web-services-spring-rest-global</module>
+        <module>web-services-spring-rest-server</module>
+    </modules>
+
+</project>
+
diff --git a/REST/SpringBoot/web-services-spring-rest-bom/pom.xml b/REST/SpringBoot/web-services-spring-rest-bom/pom.xml
new file mode 100644 (file)
index 0000000..2e5ab89
--- /dev/null
@@ -0,0 +1,159 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" 
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
+        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>1.5.1.RELEASE</version>
+    </parent>
+
+    <groupId>de.spring.webservices</groupId>
+       <artifactId>web-services-spring-rest-bom</artifactId>
+       <version>1.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+    <name>web-services-spring-rest-bom</name>
+       
+       <url>https://gumartinm.name</url>
+       <description>Web Services Spring REST Framework BOM.</description>
+       <organization>
+           <name>gumartinm</name>
+           <url>https://gumartinm.name</url>
+       </organization>
+    <scm>
+        <developerConnection>scm:git:https://git.gumartinm.name/SpringWebServicesForFun</developerConnection>
+        <url>https://git.gumartinm.name/SpringWebServicesForFun</url>
+    </scm>
+       <properties>
+        <skip.unit.tests>false</skip.unit.tests>
+        <skip.integration.tests>false</skip.integration.tests>
+               <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+       </properties>
+    <profiles>
+        <profile>
+            <id>release</id>
+            <properties>
+                <environment.profile>release</environment.profile>
+            </properties>
+            <activation>
+                <activeByDefault>true</activeByDefault>
+            </activation>
+        </profile>
+    </profiles>
+    
+    <dependencies>
+           <dependency>
+               <groupId>org.springframework.boot</groupId>
+               <artifactId>spring-boot-starter</artifactId>
+               <exclusions>
+                       <exclusion>
+                       <groupId>org.springframework.boot</groupId>
+                       <artifactId>spring-boot-starter-logging</artifactId>
+                       </exclusion>
+               </exclusions>
+               </dependency>
+               <dependency>
+               <groupId>org.springframework.boot</groupId>
+               <artifactId>spring-boot-starter-log4j2</artifactId>
+               </dependency>
+    </dependencies>
+
+       <build>
+               <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <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>
+                <configuration>
+                    <encoding>${project.build.sourceEncoding}</encoding>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <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>
+
+            <!-- Used for unit tests -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <!-- Skips unit tests if the value of skip.unit.tests property is true -->
+                    <skipTests>${skip.unit.tests}</skipTests>
+                    <!-- Excludes integration tests when unit tests are run. -->
+                    <excludes>
+                        <exclude>**/*IT.java</exclude>
+                        <exclude>**/*IntegrationTest.java</exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+
+            <!-- Used for integration tests -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-failsafe-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>integration-test</goal>
+                            <goal>verify</goal>
+                        </goals>
+                        <configuration>
+                            <!-- Skips integration tests if the value of skip.integration.tests 
+                                property is true -->
+                            <skipTests>${skip.integration.tests}</skipTests>
+                            <includes>
+                                <include>**/*IT.java</include>
+                                <include>**/*IntegrationTest.java</include>
+                            </includes>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+       </plugins>
+
+         <pluginManagement>
+            <plugins>
+                <!--
+                      It will create our running jar file.
+                      The main class must be located in: src/main/java/de/example/spring/kafka
+                      otherwise you need an explicit declaration using this property
+                      <start-class>de.exmaple.spring.kafka.Application</start-class>
+
+                      The start-class property is automatically populated by spring-boot-maven-plugin and it is
+                      used in spring-boot-starter-parent.
+                    
+                      See: http://docs.spring.io/spring-boot/docs/1.0.1.RELEASE/reference/html/build-tool-plugins-maven-plugin.html#build-tool-plugins-maven-packaging-optional-params
+                 -->
+                 <plugin>
+                     <groupId>org.springframework.boot</groupId>
+                     <artifactId>spring-boot-maven-plugin</artifactId>
+                     <version>1.4.4.RELEASE</version>
+                 </plugin>
+            </plugins>
+         </pluginManagement>
+       </build>
+</project>
diff --git a/REST/SpringBoot/web-services-spring-rest-client/pom.xml b/REST/SpringBoot/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/REST/SpringBoot/web-services-spring-rest-client/src/main/java/de/spring/webservices/main/MainTest.java b/REST/SpringBoot/web-services-spring-rest-client/src/main/java/de/spring/webservices/main/MainTest.java
new file mode 100644 (file)
index 0000000..0f066ad
--- /dev/null
@@ -0,0 +1,35 @@
+package de.spring.webservices.main;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+import de.spring.webservices.rest.business.service.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/REST/SpringBoot/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/business/service/BusinessService.java b/REST/SpringBoot/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/business/service/BusinessService.java
new file mode 100644 (file)
index 0000000..ca7a7f2
--- /dev/null
@@ -0,0 +1,11 @@
+package de.spring.webservices.rest.business.service;
+
+
+public interface BusinessService {
+
+       public void doSomethingWithCars();
+       
+       public void doSomethingWithCar(long id);
+       
+       public void createsNewCar();
+}
diff --git a/REST/SpringBoot/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/business/service/impl/BusinessServiceImpl.java b/REST/SpringBoot/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/business/service/impl/BusinessServiceImpl.java
new file mode 100644 (file)
index 0000000..b6367e8
--- /dev/null
@@ -0,0 +1,53 @@
+package de.spring.webservices.rest.business.service.impl;
+
+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.business.service.BusinessService;
+import de.spring.webservices.rest.client.service.CarClientService;
+
+@Service("businessService")
+public class BusinessServiceImpl implements BusinessService {
+       private static final Logger LOGGER = LoggerFactory.getLogger(BusinessServiceImpl.class);
+
+       private final CarClientService carClientService;
+
+       @Autowired
+       public BusinessServiceImpl(CarClientService carClientService) {
+               this.carClientService = carClientService;
+       }
+       
+       
+       @Override
+       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());
+               }
+       }
+       
+       @Override
+       public void doSomethingWithCar(long id) {               
+               Car car = carClientService.doGetCar(id);
+               LOGGER.info("Retrieved car");
+               LOGGER.info("car: " + car.getId());
+               LOGGER.info(car.getContent());
+       }
+       
+       @Override
+       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/REST/SpringBoot/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/client/service/CarClientService.java b/REST/SpringBoot/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/client/service/CarClientService.java
new file mode 100644 (file)
index 0000000..23966ba
--- /dev/null
@@ -0,0 +1,14 @@
+package de.spring.webservices.rest.client.service;
+
+import java.util.List;
+
+import de.spring.webservices.domain.Car;
+
+public interface CarClientService {
+
+       public List<Car> doGetCars();
+       
+       public Car doGetCar(long id);
+       
+       public Car doNewCar(Car car);
+}
diff --git a/REST/SpringBoot/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/client/service/impl/CarClientServiceImpl.java b/REST/SpringBoot/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/client/service/impl/CarClientServiceImpl.java
new file mode 100644 (file)
index 0000000..bdb540b
--- /dev/null
@@ -0,0 +1,58 @@
+package de.spring.webservices.rest.client.service.impl;
+
+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;
+import de.spring.webservices.rest.client.service.CarClientService;
+
+@Service("carClientService")
+public class CarClientServiceImpl implements CarClientService {
+       private static final Logger LOGGER = LoggerFactory.getLogger(CarClientServiceImpl.class);
+
+       private final String apiCarsUrl;
+       private final String apiCarUrl;
+       private final RestTemplate restTemplate;
+       
+    @Autowired
+       public CarClientServiceImpl(@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;
+       }
+
+       
+    @Override
+       public List<Car> doGetCars() {                          
+               ResponseEntity<Car[]> responseEntity = restTemplate.getForEntity(apiCarsUrl, Car[].class);
+               
+               return Arrays.asList(responseEntity.getBody());
+       }
+       
+    @Override
+       public Car doGetCar(long id) {                          
+               ResponseEntity<Car> responseEntity = restTemplate.getForEntity(
+                               apiCarUrl.replace(":id", String.valueOf(id)), Car.class);
+               
+               return responseEntity.getBody();
+       }
+       
+    @Override
+       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/REST/SpringBoot/web-services-spring-rest-client/src/main/resources/log4j2.xml b/REST/SpringBoot/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/REST/SpringBoot/web-services-spring-rest-client/src/main/resources/rest.properties b/REST/SpringBoot/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/REST/SpringBoot/web-services-spring-rest-client/src/main/resources/spring-configuration/rest-config.xml b/REST/SpringBoot/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/REST/SpringBoot/web-services-spring-rest-client/src/test/java/de/spring/webservices/rest/business/service/BusinessServiceTest.java b/REST/SpringBoot/web-services-spring-rest-client/src/test/java/de/spring/webservices/rest/business/service/BusinessServiceTest.java
new file mode 100644 (file)
index 0000000..53665c4
--- /dev/null
@@ -0,0 +1,67 @@
+package de.spring.webservices.rest.business.service;
+
+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 org.mockito.ArgumentCaptor;
+
+import de.spring.webservices.domain.Car;
+import de.spring.webservices.rest.business.service.impl.BusinessServiceImpl;
+import de.spring.webservices.rest.client.service.CarClientService;
+
+public class BusinessServiceTest {
+
+       private CarClientService carClientService;
+       private BusinessService businessService;
+       
+    @Before
+    public void createTest() {
+       carClientService = mock(CarClientService.class);
+       businessService = new BusinessServiceImpl(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);
+       }
+       
+       @Test
+       public void whenCreateNewCarThenCreateNewOne() {
+               Car expected = new Car(66L, "test");
+               ArgumentCaptor<Car> argCar = ArgumentCaptor.forClass(Car.class);
+               
+               when(carClientService.doNewCar(argCar.capture())).thenReturn(expected);
+               
+               businessService.createsNewCar();
+               
+               verify(carClientService, times(1)).doNewCar(argCar.getValue());
+       }
+}
diff --git a/REST/SpringBoot/web-services-spring-rest-client/src/test/java/de/spring/webservices/rest/client/service/CarClientServiceIntegrationTest.java b/REST/SpringBoot/web-services-spring-rest-client/src/test/java/de/spring/webservices/rest/client/service/CarClientServiceIntegrationTest.java
new file mode 100644 (file)
index 0000000..b5696be
--- /dev/null
@@ -0,0 +1,117 @@
+package de.spring.webservices.rest.client.service;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.springframework.test.web.client.match.MockRestRequestMatchers.content;
+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.http.converter.json.Jackson2ObjectMapperFactoryBean;
+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 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;
+    
+    @Autowired
+    private Jackson2ObjectMapperFactoryBean jsonObjectMapperFactory;
+
+    private MockRestServiceServer mockServer;
+
+    @Before
+    public void createTest() {
+        mockServer = MockRestServiceServer.createServer(restTemplate);
+    }
+
+       @Test
+       public void whenGetAllCarsThenRetrieveRequestedCars() throws JsonProcessingException {
+               Car expectedOne = new Car(66L, "test");
+               List<Car> expected = new ArrayList<>();
+               expected.add(expectedOne);
+               
+               mockServer.expect(requestTo(apiCarsUrl))
+                                       .andExpect(method(HttpMethod.GET))
+                                       .andRespond(withSuccess(asJsonString(expected), MediaType.APPLICATION_JSON_UTF8));
+
+               List<Car> cars = carClientService.doGetCars();
+
+               mockServer.verify();
+               
+               assertEquals(1, cars.size());
+               assertEquals(expectedOne, cars.get(0));
+       }
+       
+       @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))
+                                       .andExpect(content()
+                                                       .string(asJsonString(expected)))
+                                       .andRespond(withSuccess(asJsonString(expected), MediaType.APPLICATION_JSON_UTF8)
+                                                       .headers(headers));
+
+               Car car = carClientService.doNewCar(expected);
+
+               mockServer.verify();
+               
+               assertNotNull(car);
+               assertEquals(expected, car);
+       }
+       
+       private String asJsonString(final Object obj) throws JsonProcessingException {
+               return jsonObjectMapperFactory.getObject().writeValueAsString(obj);
+       }
+}
diff --git a/REST/SpringBoot/web-services-spring-rest-global/pom.xml b/REST/SpringBoot/web-services-spring-rest-global/pom.xml
new file mode 100644 (file)
index 0000000..744c1e3
--- /dev/null
@@ -0,0 +1,31 @@
+<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-bom</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>
+       
+       <dependencies>
+       
+               <!-- Required for using JSR-303, validations
+               <dependency>
+               <groupId>javax.validation</groupId>
+            <artifactId>validation-api</artifactId>
+            <version>${bv.api.version}</version>
+        </dependency>
+        
+        Instead we will rely on the dependencies provided by spring-boot-starter-web.
+         -->
+               <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        
+
+    </dependencies>
+</project>
diff --git a/REST/SpringBoot/web-services-spring-rest-global/src/main/java/de/spring/webservices/domain/Car.java b/REST/SpringBoot/web-services-spring-rest-global/src/main/java/de/spring/webservices/domain/Car.java
new file mode 100644 (file)
index 0000000..d062776
--- /dev/null
@@ -0,0 +1,52 @@
+package de.spring.webservices.domain;
+
+import java.util.Objects;
+
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+
+public class Car {
+
+    @NotNull
+    private Long id;
+    
+    @NotNull
+    @Size(max = 1024)
+    private String content;
+
+    // Required by Jackson :/
+    protected Car() {
+
+    }
+    
+    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() {
+      return Objects.hash(getId(), getContent());
+    }
+
+    @Override
+    public boolean equals(Object object) {
+      if (!(object instanceof Car)) {
+        return false;
+      }
+
+      final Car other = (Car) object;
+      return Objects.equals(getId(), other.getId())
+                 && Objects.equals(getContent(), other.getContent());
+    }
+
+}
diff --git a/REST/SpringBoot/web-services-spring-rest-server/logback-access.xml b/REST/SpringBoot/web-services-spring-rest-server/logback-access.xml
new file mode 100644 (file)
index 0000000..fe219ad
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <appender name="CONSOLE_ACCESS" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>%h %l %u [%t] "%r" %s %b "%i{Referer}" "%i{User-Agent}" %D "%header{X-Parent-Id}" "%header{X-Trace-Id}"</pattern>
+            <charset>utf8</charset>
+        </encoder>
+        <withJansi>true</withJansi>
+    </appender>
+
+    <appender-ref ref="CONSOLE_ACCESS" />
+</configuration>
diff --git a/REST/SpringBoot/web-services-spring-rest-server/logback.xml b/REST/SpringBoot/web-services-spring-rest-server/logback.xml
new file mode 100644 (file)
index 0000000..a7c8649
--- /dev/null
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration scan="true">
+    <property name="FILE_LOG_PATTERN" value="%date{ISO8601,GMT} %level ${PID:- } [%t] %logger : %replace(%msg \{%mdc\} %throwable){'\n','\\\\n'}%n%nopex"/>
+
+    <!--
+        To have color support in IntelliJ, please install 'Grep Console' plugin and set Enable ANSI coloring
+    -->
+    <property name="CONSOLE_LOG_PATTERN" value="%date{ISO8601,GMT} %highlight(${LOG_LEVEL_PATTERN:-%5p}) %magenta(${PID:- }) [%15.15t] %cyan(%-40.40logger{39}) : %m \{%mdc\}%n"/>
+
+
+
+    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
+            <charset>utf8</charset>
+        </encoder>
+        <withJansi>true</withJansi>
+    </appender>
+
+    
+    
+    <!-- Here you should define your loggers -->
+
+    <Logger name="org.hibernate.SQL" level="DEBUG" additivity="false">
+        <appender-ref ref="CONSOLE" />
+    </Logger>
+
+    <!--
+        Logging Hibernate QUERY PARAMETERS requires TRACE level.
+     -->
+    <Logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="TRACE" additivity="false">
+        <appender-ref ref="CONSOLE" />
+    </Logger>
+
+
+    <root level="INFO">
+        <appender-ref ref="CONSOLE" />
+    </root>
+</configuration>
diff --git a/REST/SpringBoot/web-services-spring-rest-server/pom.xml b/REST/SpringBoot/web-services-spring-rest-server/pom.xml
new file mode 100644 (file)
index 0000000..19696fd
--- /dev/null
@@ -0,0 +1,83 @@
+<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-bom</artifactId>
+               <groupId>de.spring.webservices</groupId>
+               <version>1.0-SNAPSHOT</version>
+       </parent>
+       <artifactId>web-services-spring-rest-server</artifactId>
+       <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.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <!--
+             Jackson dependency required for serializing and deserializing LocalDateTime,
+             LocalDate, etc, etc objects.
+        -->
+        <dependency>
+            <groupId>com.fasterxml.jackson.datatype</groupId>
+            <artifactId>jackson-datatype-jsr310</artifactId>
+        </dependency>
+
+
+               <!-- Unitary and integration tests -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+
+               <!-- Creates WADL from Spring REST annotations -->
+               <dependency>
+                       <groupId>org.jvnet.ws.wadl</groupId>
+                       <artifactId>wadl-core</artifactId>
+                       <version>1.1.6</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.jvnet.ws.wadl</groupId>
+                       <artifactId>wadl-client-plugin</artifactId>
+                       <version>1.1.6</version>
+               </dependency>
+               <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-oxm</artifactId>
+            <version>${spring.version}</version>
+        </dependency>
+               
+
+               <!-- API documentation -->
+               <dependency>
+                       <groupId>io.springfox</groupId>
+                       <artifactId>springfox-swagger2</artifactId>
+                       <version>2.6.1</version>
+               </dependency>
+               <dependency>
+                       <groupId>io.springfox</groupId>
+                       <artifactId>springfox-swagger-ui</artifactId>
+                       <version>2.6.1</version>
+               </dependency>
+               
+       </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+             </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/REST/SpringBoot/web-services-spring-rest-server/src/main/java/de/spring/webservices/Application.java b/REST/SpringBoot/web-services-spring-rest-server/src/main/java/de/spring/webservices/Application.java
new file mode 100644 (file)
index 0000000..f19933a
--- /dev/null
@@ -0,0 +1,23 @@
+package de.spring.webservices;
+
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+
+@SpringBootApplication
+public class Application {
+
+  public static void main(String[] args) {
+    SpringApplication.run(Application.class);
+  }
+
+
+  @Bean
+  CommandLineRunner lookup() {
+    return args -> {
+
+    };
+  }
+
+}
diff --git a/REST/SpringBoot/web-services-spring-rest-server/src/main/java/de/spring/webservices/configuration/JacksonConfiguration.java b/REST/SpringBoot/web-services-spring-rest-server/src/main/java/de/spring/webservices/configuration/JacksonConfiguration.java
new file mode 100644 (file)
index 0000000..2a54a3b
--- /dev/null
@@ -0,0 +1,26 @@
+package de.spring.webservices.configuration;
+
+import javax.inject.Inject;
+
+import org.springframework.context.annotation.Configuration;
+
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.MapperFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+
+@Configuration
+public class JacksonConfiguration {
+
+  @Inject
+  public void configureJackson(ObjectMapper jackson2ObjectMapper) {
+         jackson2ObjectMapper
+               .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
+        .disable(MapperFeature.DEFAULT_VIEW_INCLUSION)
+        .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)
+        .enable(SerializationFeature.INDENT_OUTPUT)
+        .registerModule(new JavaTimeModule());
+  }
+  
+}
diff --git a/REST/SpringBoot/web-services-spring-rest-server/src/main/java/de/spring/webservices/configuration/Swagger2Configuration.java b/REST/SpringBoot/web-services-spring-rest-server/src/main/java/de/spring/webservices/configuration/Swagger2Configuration.java
new file mode 100644 (file)
index 0000000..c4ea5bf
--- /dev/null
@@ -0,0 +1,63 @@
+package de.spring.webservices.configuration;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static springfox.documentation.builders.RequestHandlerSelectors.basePackage;
+import static springfox.documentation.builders.RequestHandlerSelectors.withMethodAnnotation;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.ResponseMessageBuilder;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.Contact;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger.web.UiConfiguration;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+/**
+ * Go to URL: http://localhost:8080/swagger-ui.html#/
+ *
+ */
+@Configuration
+@EnableSwagger2
+public class Swagger2Configuration {
+       
+       @Bean
+       public Docket documentation() {
+               return new Docket(DocumentationType.SWAGGER_2)
+                               .select()
+                                       .apis(withMethodAnnotation(RequestMapping.class))
+                                       .apis(basePackage("de.spring.webservices.rest.controller"))
+                                       .paths(PathSelectors.any())
+                                       .build()
+                                       .globalResponseMessage(RequestMethod.GET,
+                                                       newArrayList(new ResponseMessageBuilder()
+                                                                       .code(500).message("Global server custom error message").build()))
+                       .useDefaultResponseMessages(false)
+                       .apiInfo(metadata())
+                       .enable(true);
+       }
+
+       @Bean
+       UiConfiguration uiConfig() {
+               return new UiConfiguration(null);
+       }
+       
+       private static ApiInfo metadata() {
+               return new ApiInfoBuilder()
+                               .title("gumartinm REST API")
+                               .description("Gustavo Martin Morcuende")
+                               .version("1.0-SNAPSHOT")
+                       .contact(doContact())
+                       .build();
+       }
+
+       private static Contact doContact() {
+               return new Contact("Gustavo Martin", "https://gumartinm.name", "");
+       }
+}
diff --git a/REST/SpringBoot/web-services-spring-rest-server/src/main/java/de/spring/webservices/configuration/ValidatorConfiguration.java b/REST/SpringBoot/web-services-spring-rest-server/src/main/java/de/spring/webservices/configuration/ValidatorConfiguration.java
new file mode 100644 (file)
index 0000000..ff41038
--- /dev/null
@@ -0,0 +1,15 @@
+package de.spring.webservices.configuration;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
+
+@Configuration
+public class ValidatorConfiguration {
+
+         @Bean
+         public LocalValidatorFactoryBean localValidatorFactoryBean() {
+           return new LocalValidatorFactoryBean();
+         }
+
+}
diff --git a/REST/SpringBoot/web-services-spring-rest-server/src/main/java/de/spring/webservices/configuration/WadlConfiguration.java b/REST/SpringBoot/web-services-spring-rest-server/src/main/java/de/spring/webservices/configuration/WadlConfiguration.java
new file mode 100644 (file)
index 0000000..d128661
--- /dev/null
@@ -0,0 +1,22 @@
+package de.spring.webservices.configuration;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.converter.xml.MarshallingHttpMessageConverter;
+import org.springframework.oxm.jaxb.Jaxb2Marshaller;
+
+@Configuration
+public class WadlConfiguration {
+       
+       @Bean
+       public Jaxb2Marshaller marshaller() {
+               Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
+           marshaller.setPackagesToScan("org.jvnet.ws.wadl");
+           return marshaller;    
+       }
+
+       @Bean
+       public MarshallingHttpMessageConverter marshallingHttpMessageConverter(Jaxb2Marshaller marshaller) {
+               return new MarshallingHttpMessageConverter(marshaller);
+       }
+}
diff --git a/REST/SpringBoot/web-services-spring-rest-server/src/main/java/de/spring/webservices/rest/controller/CarController.java b/REST/SpringBoot/web-services-spring-rest-server/src/main/java/de/spring/webservices/rest/controller/CarController.java
new file mode 100644 (file)
index 0000000..a440177
--- /dev/null
@@ -0,0 +1,117 @@
+package de.spring.webservices.rest.controller;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+
+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.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+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.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.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import io.swagger.annotations.ResponseHeader;
+
+@RestController
+@RequestMapping("/api/cars/")
+public class CarController {
+       
+       private static final Logger LOGGER = LoggerFactory.getLogger(CarController.class);
+    private static final String TEMPLATE = "Car: %s";
+    
+    @NotNull
+    private final AtomicLong counter = new AtomicLong();
+
+       @ApiOperation(value = "Get all available cars", nickname = "getAllCars", responseContainer="List", response = Car.class)
+    @ApiResponses({
+        @ApiResponse(code =  404, message ="Specific getCars not found"),
+        @ApiResponse(code =  400, message ="Specific getCars invalid input")
+    })
+       @GetMapping(produces = { MediaType.APPLICATION_JSON_UTF8_VALUE })
+    @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;
+    }
+
+       @ApiOperation(value = "Get one car", nickname = "getOneCar", response = Car.class)
+    @ApiResponses({
+        @ApiResponse(code =  404, message ="Specific getCar not found"),
+        @ApiResponse(code =  400, message ="Specific getCar invalid input")
+    })
+    @GetMapping(value = "{id}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+    @ResponseStatus(HttpStatus.OK)
+    public Car car(@RequestHeader(value = "MY_HEADER", required = false) String specialHeader,
+               @ApiParam(name = "id", value = "Car id", required = true) @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));
+    }
+    
+       @ApiOperation(code =  201, value = "Create one new car", nickname = "createNewCar")
+    @ApiResponses({
+       @ApiResponse(code =  201, message ="Specific createCar with header",
+                       responseHeaders = { @ResponseHeader(name = HttpHeaders.LOCATION) }, response = Car.class),
+        @ApiResponse(code =  404, message ="Specific createCar not found"),
+        @ApiResponse(code =  400, message ="Specific createCar invalid input")
+    })
+    @PostMapping(consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+       @ResponseStatus(HttpStatus.CREATED)
+    public ResponseEntity<Car> create(@RequestBody @Valid 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/REST/SpringBoot/web-services-spring-rest-server/src/main/java/de/spring/webservices/rest/wadl/WADLController.java b/REST/SpringBoot/web-services-spring-rest-server/src/main/java/de/spring/webservices/rest/wadl/WADLController.java
new file mode 100644 (file)
index 0000000..1125157
--- /dev/null
@@ -0,0 +1,236 @@
+package de.spring.webservices.rest.wadl;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.xml.namespace.QName;
+
+import org.apache.commons.lang.StringUtils;
+import org.jvnet.ws.wadl.Application;
+import org.jvnet.ws.wadl.Doc;
+import org.jvnet.ws.wadl.Param;
+import org.jvnet.ws.wadl.ParamStyle;
+import org.jvnet.ws.wadl.Representation;
+import org.jvnet.ws.wadl.Request;
+import org.jvnet.ws.wadl.Resource;
+import org.jvnet.ws.wadl.Resources;
+import org.jvnet.ws.wadl.Response;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.ValueConstants;
+import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
+import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
+
+/**
+ * Taken from: http://javattitude.com/2014/05/26/wadl-generator-for-spring-rest/
+ * 
+ * With some modifications.
+ *
+ */
+@Controller
+@RequestMapping("/rest.wadl")
+public class WADLController {
+       private static final String NAMESPACE_URI = "http://www.w3.org/2001/XMLSchema" ;
+       private static final String WADL_TITLE = "Spring REST Service WADL";
+       
+    private final AbstractHandlerMethodMapping<RequestMappingInfo> handlerMapping;
+    private final ApplicationContext context;
+    
+    @Autowired
+       public WADLController(AbstractHandlerMethodMapping<RequestMappingInfo> handlerMapping, ApplicationContext context) {
+               this.handlerMapping = handlerMapping;
+               this.context = context;
+       }
+       
+    @RequestMapping(produces = { MediaType.APPLICATION_XML_VALUE }, method=RequestMethod.GET ) 
+    public @ResponseBody Application generateWadl(HttpServletRequest request) {
+        Application result = new Application();
+        
+        Doc doc = new Doc();
+        doc.setTitle(WADL_TITLE);
+        result.getDoc().add(doc);
+        
+        Resources wadlResources = new Resources();
+        wadlResources.setBase(getBaseUrl(request));
+                 
+        handlerMapping.getHandlerMethods().forEach( (mappingInfo, handlerMethod) -> {
+            Object object = handlerMethod.getBean();
+            Object bean = context.getBean(object.toString());
+            if(!bean.getClass().isAnnotationPresent(RestController.class)) {
+               return;
+            }
+            
+            mappingInfo.getMethodsCondition().getMethods().forEach(httpMethod -> {
+               Resource wadlResource = null; 
+                org.jvnet.ws.wadl.Method wadlMethod = new org.jvnet.ws.wadl.Method();
+     
+                Set<String> pattern =  mappingInfo.getPatternsCondition().getPatterns();
+                for (String uri : pattern) {
+                       wadlResource = createOrFind(uri, wadlResources); 
+                    wadlResource.setPath(uri);      
+                }
+                 
+                wadlMethod.setName(httpMethod.name());
+                Method javaMethod = handlerMethod.getMethod();
+                wadlMethod.setId(javaMethod.getName());
+                Doc wadlDocMethod = new Doc();
+                wadlDocMethod.setTitle(javaMethod.getDeclaringClass().getSimpleName() + "." + javaMethod.getName());
+                wadlMethod.getDoc().add(wadlDocMethod);
+                 
+                // Request
+                Request wadlRequest = new Request();
+                Annotation[][] annotations = javaMethod.getParameterAnnotations();
+                Class<?>[] paramTypes = javaMethod.getParameterTypes();
+                int i = 0;
+                for (Annotation[] annotation : annotations) {
+                       Class<?> paramType =paramTypes[i];
+                       i++;
+                    for (Annotation annotation2 : annotation) {
+                    
+                       Param wadlParam = doParam(annotation2, paramType);
+                       if (wadlParam != null) {
+                               wadlRequest.getParam().add(wadlParam);
+                       }
+                    }
+                }
+                if (!wadlRequest.getParam().isEmpty() ) {
+                    wadlMethod.setRequest(wadlRequest);
+                }
+                 
+                // Response
+                Set<MediaType> mediaTypes = mappingInfo.getProducesCondition().getProducibleMediaTypes();
+                if (!mediaTypes.isEmpty()) {
+                       ResponseStatus status = handlerMethod.getMethodAnnotation(ResponseStatus.class);
+                    Response wadlResponse = doResponse(mediaTypes, status);
+                    wadlMethod.getResponse().add(wadlResponse);
+                }
+                
+                
+                wadlResource.getMethodOrResource().add(wadlMethod);          
+            });
+             
+        });
+        result.getResources().add(wadlResources);
+         
+        return result;
+    }
+    
+    private Param doParam(Annotation annotation2, Class<?> paramType) {
+       Param wadlParam = null;
+       
+        if (annotation2 instanceof RequestParam ) {
+            RequestParam param = (RequestParam)annotation2;
+            
+            wadlParam = new Param();
+            QName nm = convertJavaToXMLType(paramType);
+            if (StringUtils.isNotEmpty(nm.getLocalPart())) {
+               wadlParam.setType(nm);
+            }
+            wadlParam.setName(param.value());
+            
+            
+            if (!ValueConstants.DEFAULT_NONE.equals(param.defaultValue())) {
+                String defaultValue = cleanDefault(param.defaultValue());
+                if (StringUtils.isNotEmpty(defaultValue) ) {
+                    wadlParam.setDefault(defaultValue);
+                }
+            }
+
+            wadlParam.setStyle(ParamStyle.QUERY);
+            wadlParam.setRequired(param.required());       
+        } else if (annotation2 instanceof PathVariable ) {
+            PathVariable param = (PathVariable)annotation2;
+            
+            wadlParam = new Param();                            
+            QName nm = convertJavaToXMLType(paramType);
+            if (StringUtils.isNotEmpty(nm.getLocalPart())) {
+               wadlParam.setType(nm);
+            }
+            wadlParam.setName(param.value());
+            
+            
+            wadlParam.setStyle(ParamStyle.TEMPLATE);
+            wadlParam.setRequired(true);
+        }
+        
+        return wadlParam;
+    }
+     
+    private Response doResponse(Set<MediaType> mediaTypes, ResponseStatus status) {
+       Response wadlResponse = new Response();
+        
+        mediaTypes.forEach(mediaType -> {
+            Representation wadlRepresentation = new Representation();
+            wadlRepresentation.setMediaType(mediaType.toString());
+            wadlResponse.getRepresentation().add(wadlRepresentation);
+        });
+        
+        wadlResponse.getStatus().add(getResposeValue(status));
+
+        return wadlResponse;
+    }
+    
+    private long getResposeValue(ResponseStatus status) {
+       if(status == null) {
+               return HttpStatus.OK.value();
+        } else {
+            HttpStatus httpcode = status.value();
+            return httpcode.value();
+        }
+    }
+    
+    private QName convertJavaToXMLType(Class<?> type) {
+       QName nm = new QName("");
+       String classname = type.toString();
+       classname = classname.toLowerCase();
+       
+               if (classname.indexOf("string") >= 0) {
+                       nm = new QName(NAMESPACE_URI, "string", "xs");
+               } else if (classname.indexOf("integer") >= 0) {
+                       nm = new QName(NAMESPACE_URI, "int", "xs");
+               } else if (classname.indexOf("long") >= 0) {
+                       nm = new QName(NAMESPACE_URI, "long", "xs");
+               }
+       
+       return nm;
+    }
+    
+    private Resource createOrFind(String uri, Resources wadResources) {
+         List<Resource> current = wadResources.getResource();
+         for(Resource resource:current) {
+                 if(resource.getPath().equalsIgnoreCase(uri)){
+                         return resource;
+                 }
+         }
+         Resource wadlResource = new Resource();
+         current.add(wadlResource);
+         return wadlResource;
+    }
+    
+    private String getBaseUrl(HttpServletRequest request) {
+        String requestUri = request.getRequestURI();
+        int index = requestUri.lastIndexOf('/');
+        requestUri = requestUri.substring(0, index);
+        
+        return request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + requestUri;
+    }
+     
+    private String cleanDefault(String value) {
+        value = value.replaceAll("\t", "");
+        value = value.replaceAll("\n", "");
+        return value;
+    }
+}
diff --git a/REST/SpringBoot/web-services-spring-rest-server/src/main/resources/application.yml b/REST/SpringBoot/web-services-spring-rest-server/src/main/resources/application.yml
new file mode 100644 (file)
index 0000000..7a01bea
--- /dev/null
@@ -0,0 +1,13 @@
+spring:
+  application:
+    name: web-services-spring-rest-server
+  main:
+    banner-mode: "LOG"
+
+server:
+  port: 8080
+  
+springfox.documentation.swagger.v2.path: /schema
+
+logging:
+  config: classpath:log4j2.xml
diff --git a/REST/SpringBoot/web-services-spring-rest-server/src/main/resources/banner.txt b/REST/SpringBoot/web-services-spring-rest-server/src/main/resources/banner.txt
new file mode 100644 (file)
index 0000000..2782065
--- /dev/null
@@ -0,0 +1,9 @@
+   _____            _              __          __  _        _____                 _               
+  / ____|          (_)             \ \        / / | |      / ____|               (_)              
+ | (___  _ __  _ __ _ _ __   __ _   \ \  /\  / /__| |__   | (___   ___ _ ____   ___  ___ ___  ___ 
+  \___ \| '_ \| '__| | '_ \ / _` |   \ \/  \/ / _ \ '_ \   \___ \ / _ \ '__\ \ / / |/ __/ _ \/ __|
+  ____) | |_) | |  | | | | | (_| |    \  /\  /  __/ |_) |  ____) |  __/ |   \ V /| | (_|  __/\__ \
+ |_____/| .__/|_|  |_|_| |_|\__, |     \/  \/ \___|_.__/  |_____/ \___|_|    \_/ |_|\___\___||___/
+        | |                  __/ |                                                                
+        |_|                 |___/                       
+                ${application.title}                 ${application.formatted-version}                                          
\ No newline at end of file
diff --git a/REST/SpringBoot/web-services-spring-rest-server/src/main/resources/log4j2.xml b/REST/SpringBoot/web-services-spring-rest-server/src/main/resources/log4j2.xml
new file mode 100644 (file)
index 0000000..21f1ac3
--- /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>
\ No newline at end of file
diff --git a/REST/SpringBoot/web-services-spring-rest-server/src/main/webapp/WEB-INF/web.xml b/REST/SpringBoot/web-services-spring-rest-server/src/main/webapp/WEB-INF/web.xml
new file mode 100644 (file)
index 0000000..6c9c1d0
--- /dev/null
@@ -0,0 +1,41 @@
+<?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>
+        <!-- REQUIRED PATTERN BY swagger-ui. IT DOESN'T WORK WITH ANY OTHER o.O -->
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+</web-app>
diff --git a/REST/SpringBoot/web-services-spring-rest-server/src/test/java/de/spring/webservices/rest/controller/CarControllerIntegrationTest.java b/REST/SpringBoot/web-services-spring-rest-server/src/test/java/de/spring/webservices/rest/controller/CarControllerIntegrationTest.java
new file mode 100644 (file)
index 0000000..db04517
--- /dev/null
@@ -0,0 +1,105 @@
+package de.spring.webservices.rest.controller;
+
+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 javax.inject.Inject;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+//import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.MapperFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+
+import de.spring.webservices.domain.Car;
+
+
+@RunWith(SpringRunner.class)
+@WebMvcTest(CarController.class)
+public class CarControllerIntegrationTest {
+       
+       // For injecting and mocking services which could be  used in the Controller under test.
+       //@MockBean
+       //private CarService carService;
+       
+       @Inject
+       private WebApplicationContext context;
+       
+       @Inject
+       private ObjectMapper objectMapper;
+       
+       private MockMvc mockMvc;
+       
+    @Before
+    public void setup() {        
+        mockMvc = MockMvcBuilders
+                .webAppContextSetup(context)
+                .build();
+
+            objectMapper
+            .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
+            .disable(MapperFeature.DEFAULT_VIEW_INCLUSION)
+            .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)
+            .enable(SerializationFeature.INDENT_OUTPUT)
+            .registerModule(new JavaTimeModule());
+    }
+
+       @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(objectMapper.writeValueAsString(car))
+                               .accept(MediaType.APPLICATION_JSON_UTF8))
+               
+               .andExpect(status().isCreated())
+               .andExpect(jsonPath("id", any(Integer.class)))
+               .andExpect(jsonPath("content", is("Car: 2")))
+               .andExpect(header().string(HttpHeaders.LOCATION, "/api/cars/2"))
+               .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8));
+       }
+}
diff --git a/REST/SpringBoot/web-services-spring-rest-server/src/test/resources/application.yml b/REST/SpringBoot/web-services-spring-rest-server/src/test/resources/application.yml
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/REST/web-services-spring-rest-client/pom.xml b/REST/web-services-spring-rest-client/pom.xml
deleted file mode 100644 (file)
index 276b3db..0000000
+++ /dev/null
@@ -1,61 +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>
-       <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/REST/web-services-spring-rest-client/src/main/java/de/spring/webservices/main/MainTest.java b/REST/web-services-spring-rest-client/src/main/java/de/spring/webservices/main/MainTest.java
deleted file mode 100644 (file)
index 0f066ad..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-package de.spring.webservices.main;
-
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.support.ClassPathXmlApplicationContext;
-
-import de.spring.webservices.rest.business.service.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/REST/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/business/service/BusinessService.java b/REST/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/business/service/BusinessService.java
deleted file mode 100644 (file)
index ca7a7f2..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-package de.spring.webservices.rest.business.service;
-
-
-public interface BusinessService {
-
-       public void doSomethingWithCars();
-       
-       public void doSomethingWithCar(long id);
-       
-       public void createsNewCar();
-}
diff --git a/REST/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/business/service/impl/BusinessServiceImpl.java b/REST/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/business/service/impl/BusinessServiceImpl.java
deleted file mode 100644 (file)
index b6367e8..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-package de.spring.webservices.rest.business.service.impl;
-
-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.business.service.BusinessService;
-import de.spring.webservices.rest.client.service.CarClientService;
-
-@Service("businessService")
-public class BusinessServiceImpl implements BusinessService {
-       private static final Logger LOGGER = LoggerFactory.getLogger(BusinessServiceImpl.class);
-
-       private final CarClientService carClientService;
-
-       @Autowired
-       public BusinessServiceImpl(CarClientService carClientService) {
-               this.carClientService = carClientService;
-       }
-       
-       
-       @Override
-       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());
-               }
-       }
-       
-       @Override
-       public void doSomethingWithCar(long id) {               
-               Car car = carClientService.doGetCar(id);
-               LOGGER.info("Retrieved car");
-               LOGGER.info("car: " + car.getId());
-               LOGGER.info(car.getContent());
-       }
-       
-       @Override
-       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/REST/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/client/service/CarClientService.java b/REST/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/client/service/CarClientService.java
deleted file mode 100644 (file)
index 23966ba..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-package de.spring.webservices.rest.client.service;
-
-import java.util.List;
-
-import de.spring.webservices.domain.Car;
-
-public interface CarClientService {
-
-       public List<Car> doGetCars();
-       
-       public Car doGetCar(long id);
-       
-       public Car doNewCar(Car car);
-}
diff --git a/REST/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/client/service/impl/CarClientServiceImpl.java b/REST/web-services-spring-rest-client/src/main/java/de/spring/webservices/rest/client/service/impl/CarClientServiceImpl.java
deleted file mode 100644 (file)
index bdb540b..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-package de.spring.webservices.rest.client.service.impl;
-
-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;
-import de.spring.webservices.rest.client.service.CarClientService;
-
-@Service("carClientService")
-public class CarClientServiceImpl implements CarClientService {
-       private static final Logger LOGGER = LoggerFactory.getLogger(CarClientServiceImpl.class);
-
-       private final String apiCarsUrl;
-       private final String apiCarUrl;
-       private final RestTemplate restTemplate;
-       
-    @Autowired
-       public CarClientServiceImpl(@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;
-       }
-
-       
-    @Override
-       public List<Car> doGetCars() {                          
-               ResponseEntity<Car[]> responseEntity = restTemplate.getForEntity(apiCarsUrl, Car[].class);
-               
-               return Arrays.asList(responseEntity.getBody());
-       }
-       
-    @Override
-       public Car doGetCar(long id) {                          
-               ResponseEntity<Car> responseEntity = restTemplate.getForEntity(
-                               apiCarUrl.replace(":id", String.valueOf(id)), Car.class);
-               
-               return responseEntity.getBody();
-       }
-       
-    @Override
-       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/REST/web-services-spring-rest-client/src/main/resources/log4j2.xml b/REST/web-services-spring-rest-client/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/REST/web-services-spring-rest-client/src/main/resources/rest.properties b/REST/web-services-spring-rest-client/src/main/resources/rest.properties
deleted file mode 100644 (file)
index 00255b0..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-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/REST/web-services-spring-rest-client/src/main/resources/spring-configuration/rest-config.xml b/REST/web-services-spring-rest-client/src/main/resources/spring-configuration/rest-config.xml
deleted file mode 100644 (file)
index 5f4e873..0000000
+++ /dev/null
@@ -1,39 +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"
-       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/REST/web-services-spring-rest-client/src/test/java/de/spring/webservices/rest/business/service/BusinessServiceTest.java b/REST/web-services-spring-rest-client/src/test/java/de/spring/webservices/rest/business/service/BusinessServiceTest.java
deleted file mode 100644 (file)
index 53665c4..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-package de.spring.webservices.rest.business.service;
-
-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 org.mockito.ArgumentCaptor;
-
-import de.spring.webservices.domain.Car;
-import de.spring.webservices.rest.business.service.impl.BusinessServiceImpl;
-import de.spring.webservices.rest.client.service.CarClientService;
-
-public class BusinessServiceTest {
-
-       private CarClientService carClientService;
-       private BusinessService businessService;
-       
-    @Before
-    public void createTest() {
-       carClientService = mock(CarClientService.class);
-       businessService = new BusinessServiceImpl(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);
-       }
-       
-       @Test
-       public void whenCreateNewCarThenCreateNewOne() {
-               Car expected = new Car(66L, "test");
-               ArgumentCaptor<Car> argCar = ArgumentCaptor.forClass(Car.class);
-               
-               when(carClientService.doNewCar(argCar.capture())).thenReturn(expected);
-               
-               businessService.createsNewCar();
-               
-               verify(carClientService, times(1)).doNewCar(argCar.getValue());
-       }
-}
diff --git a/REST/web-services-spring-rest-client/src/test/java/de/spring/webservices/rest/client/service/CarClientServiceIntegrationTest.java b/REST/web-services-spring-rest-client/src/test/java/de/spring/webservices/rest/client/service/CarClientServiceIntegrationTest.java
deleted file mode 100644 (file)
index b5696be..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-package de.spring.webservices.rest.client.service;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.springframework.test.web.client.match.MockRestRequestMatchers.content;
-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.http.converter.json.Jackson2ObjectMapperFactoryBean;
-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 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;
-    
-    @Autowired
-    private Jackson2ObjectMapperFactoryBean jsonObjectMapperFactory;
-
-    private MockRestServiceServer mockServer;
-
-    @Before
-    public void createTest() {
-        mockServer = MockRestServiceServer.createServer(restTemplate);
-    }
-
-       @Test
-       public void whenGetAllCarsThenRetrieveRequestedCars() throws JsonProcessingException {
-               Car expectedOne = new Car(66L, "test");
-               List<Car> expected = new ArrayList<>();
-               expected.add(expectedOne);
-               
-               mockServer.expect(requestTo(apiCarsUrl))
-                                       .andExpect(method(HttpMethod.GET))
-                                       .andRespond(withSuccess(asJsonString(expected), MediaType.APPLICATION_JSON_UTF8));
-
-               List<Car> cars = carClientService.doGetCars();
-
-               mockServer.verify();
-               
-               assertEquals(1, cars.size());
-               assertEquals(expectedOne, cars.get(0));
-       }
-       
-       @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))
-                                       .andExpect(content()
-                                                       .string(asJsonString(expected)))
-                                       .andRespond(withSuccess(asJsonString(expected), MediaType.APPLICATION_JSON_UTF8)
-                                                       .headers(headers));
-
-               Car car = carClientService.doNewCar(expected);
-
-               mockServer.verify();
-               
-               assertNotNull(car);
-               assertEquals(expected, car);
-       }
-       
-       private String asJsonString(final Object obj) throws JsonProcessingException {
-               return jsonObjectMapperFactory.getObject().writeValueAsString(obj);
-       }
-}
diff --git a/REST/web-services-spring-rest-global/pom.xml b/REST/web-services-spring-rest-global/pom.xml
deleted file mode 100644 (file)
index c726115..0000000
+++ /dev/null
@@ -1,12 +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>
-       <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/REST/web-services-spring-rest-global/src/main/java/de/spring/webservices/domain/Car.java b/REST/web-services-spring-rest-global/src/main/java/de/spring/webservices/domain/Car.java
deleted file mode 100644 (file)
index cdfaa07..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-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/REST/web-services-spring-rest-server/pom.xml b/REST/web-services-spring-rest-server/pom.xml
deleted file mode 100644 (file)
index 144a67c..0000000
+++ /dev/null
@@ -1,139 +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>
-       <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>
-
-               <!-- Creates WADL from Spring REST annotations -->
-               <dependency>
-                       <groupId>org.jvnet.ws.wadl</groupId>
-                       <artifactId>wadl-core</artifactId>
-                       <version>1.1.6</version>
-               </dependency>
-               <dependency>
-                       <groupId>org.jvnet.ws.wadl</groupId>
-                       <artifactId>wadl-client-plugin</artifactId>
-                       <version>1.1.6</version>
-               </dependency>
-               <dependency>
-               <groupId>org.springframework</groupId>
-               <artifactId>spring-oxm</artifactId>
-               <version>4.2.4.RELEASE</version>
-               </dependency>
-
-               <!-- API documentation -->
-               <dependency>
-                       <groupId>io.springfox</groupId>
-                       <artifactId>springfox-swagger1</artifactId>
-                       <version>2.3.1</version>
-               </dependency>
-               <dependency>
-                       <groupId>io.springfox</groupId>
-                       <artifactId>springfox-swagger-ui</artifactId>
-                       <version>2.3.1</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>
-               </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/REST/web-services-spring-rest-server/src/main/java/de/spring/webservices/doc/Swagger2Configuration.java b/REST/web-services-spring-rest-server/src/main/java/de/spring/webservices/doc/Swagger2Configuration.java
deleted file mode 100644 (file)
index df71590..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-package de.spring.webservices.doc;
-
-import static com.google.common.collect.Lists.newArrayList;
-
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.ComponentScan;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-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.builders.ResponseMessageBuilder;
-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.swagger1.annotations.EnableSwagger;
-
-@Configuration
-@EnableWebMvc
-@EnableSwagger
-@ComponentScan("de.spring.webservices.rest.controller")
-public class Swagger2Configuration {
-       
-       @Bean
-       public Docket documentation() {
-               return new Docket(DocumentationType.SWAGGER_12)
-                               .select()
-                                       .apis(RequestHandlerSelectors.withMethodAnnotation(RequestMapping.class))
-                                       .paths(PathSelectors.any())
-                                       .build()
-                                       .globalResponseMessage(RequestMethod.GET,
-                                                       newArrayList(new ResponseMessageBuilder()
-                                                                       .code(500).message("Global server custom error message").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/REST/web-services-spring-rest-server/src/main/java/de/spring/webservices/rest/controller/CarController.java b/REST/web-services-spring-rest-server/src/main/java/de/spring/webservices/rest/controller/CarController.java
deleted file mode 100644 (file)
index 49acf64..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-package de.spring.webservices.rest.controller;
-
-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.ApiParam;
-import io.swagger.annotations.ApiResponse;
-import io.swagger.annotations.ApiResponses;
-import io.swagger.annotations.ResponseHeader;
-
-@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();
-
-       @ApiOperation(value = "Get all available cars", nickname = "getAllCars", responseContainer="List", response = Car.class)
-    @ApiResponses({
-        @ApiResponse(code =  404, message ="Specific getCars not found"),
-        @ApiResponse(code =  400, message ="Specific getCars 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;
-    }
-
-       @ApiOperation(value = "Get one car", nickname = "getOneCar", response = Car.class)
-    @ApiResponses({
-        @ApiResponse(code =  404, message ="Specific getCar not found"),
-        @ApiResponse(code =  400, message ="Specific getCar 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,
-               @ApiParam(name = "id", value = "Car id", required = true) @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));
-    }
-    
-       @ApiOperation(code =  201, value = "Create one new car", nickname = "createNewCar")
-    @ApiResponses({
-       @ApiResponse(code =  201, message ="Specific createCar with header",
-                       responseHeaders = { @ResponseHeader(name = HttpHeaders.LOCATION) }, response = Car.class),
-        @ApiResponse(code =  404, message ="Specific createCar not found"),
-        @ApiResponse(code =  400, message ="Specific createCar invalid input")
-    })
-    @RequestMapping(consumes = MediaType.APPLICATION_JSON_UTF8_VALUE,
-               produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.POST)
-       @ResponseStatus(HttpStatus.CREATED)
-    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/REST/web-services-spring-rest-server/src/main/java/de/spring/webservices/rest/wadl/WADLController.java b/REST/web-services-spring-rest-server/src/main/java/de/spring/webservices/rest/wadl/WADLController.java
deleted file mode 100644 (file)
index 1125157..0000000
+++ /dev/null
@@ -1,236 +0,0 @@
-package de.spring.webservices.rest.wadl;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Method;
-import java.util.List;
-import java.util.Set;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.xml.namespace.QName;
-
-import org.apache.commons.lang.StringUtils;
-import org.jvnet.ws.wadl.Application;
-import org.jvnet.ws.wadl.Doc;
-import org.jvnet.ws.wadl.Param;
-import org.jvnet.ws.wadl.ParamStyle;
-import org.jvnet.ws.wadl.Representation;
-import org.jvnet.ws.wadl.Request;
-import org.jvnet.ws.wadl.Resource;
-import org.jvnet.ws.wadl.Resources;
-import org.jvnet.ws.wadl.Response;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.ApplicationContext;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.ResponseBody;
-import org.springframework.web.bind.annotation.ResponseStatus;
-import org.springframework.web.bind.annotation.RestController;
-import org.springframework.web.bind.annotation.ValueConstants;
-import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
-import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
-
-/**
- * Taken from: http://javattitude.com/2014/05/26/wadl-generator-for-spring-rest/
- * 
- * With some modifications.
- *
- */
-@Controller
-@RequestMapping("/rest.wadl")
-public class WADLController {
-       private static final String NAMESPACE_URI = "http://www.w3.org/2001/XMLSchema" ;
-       private static final String WADL_TITLE = "Spring REST Service WADL";
-       
-    private final AbstractHandlerMethodMapping<RequestMappingInfo> handlerMapping;
-    private final ApplicationContext context;
-    
-    @Autowired
-       public WADLController(AbstractHandlerMethodMapping<RequestMappingInfo> handlerMapping, ApplicationContext context) {
-               this.handlerMapping = handlerMapping;
-               this.context = context;
-       }
-       
-    @RequestMapping(produces = { MediaType.APPLICATION_XML_VALUE }, method=RequestMethod.GET ) 
-    public @ResponseBody Application generateWadl(HttpServletRequest request) {
-        Application result = new Application();
-        
-        Doc doc = new Doc();
-        doc.setTitle(WADL_TITLE);
-        result.getDoc().add(doc);
-        
-        Resources wadlResources = new Resources();
-        wadlResources.setBase(getBaseUrl(request));
-                 
-        handlerMapping.getHandlerMethods().forEach( (mappingInfo, handlerMethod) -> {
-            Object object = handlerMethod.getBean();
-            Object bean = context.getBean(object.toString());
-            if(!bean.getClass().isAnnotationPresent(RestController.class)) {
-               return;
-            }
-            
-            mappingInfo.getMethodsCondition().getMethods().forEach(httpMethod -> {
-               Resource wadlResource = null; 
-                org.jvnet.ws.wadl.Method wadlMethod = new org.jvnet.ws.wadl.Method();
-     
-                Set<String> pattern =  mappingInfo.getPatternsCondition().getPatterns();
-                for (String uri : pattern) {
-                       wadlResource = createOrFind(uri, wadlResources); 
-                    wadlResource.setPath(uri);      
-                }
-                 
-                wadlMethod.setName(httpMethod.name());
-                Method javaMethod = handlerMethod.getMethod();
-                wadlMethod.setId(javaMethod.getName());
-                Doc wadlDocMethod = new Doc();
-                wadlDocMethod.setTitle(javaMethod.getDeclaringClass().getSimpleName() + "." + javaMethod.getName());
-                wadlMethod.getDoc().add(wadlDocMethod);
-                 
-                // Request
-                Request wadlRequest = new Request();
-                Annotation[][] annotations = javaMethod.getParameterAnnotations();
-                Class<?>[] paramTypes = javaMethod.getParameterTypes();
-                int i = 0;
-                for (Annotation[] annotation : annotations) {
-                       Class<?> paramType =paramTypes[i];
-                       i++;
-                    for (Annotation annotation2 : annotation) {
-                    
-                       Param wadlParam = doParam(annotation2, paramType);
-                       if (wadlParam != null) {
-                               wadlRequest.getParam().add(wadlParam);
-                       }
-                    }
-                }
-                if (!wadlRequest.getParam().isEmpty() ) {
-                    wadlMethod.setRequest(wadlRequest);
-                }
-                 
-                // Response
-                Set<MediaType> mediaTypes = mappingInfo.getProducesCondition().getProducibleMediaTypes();
-                if (!mediaTypes.isEmpty()) {
-                       ResponseStatus status = handlerMethod.getMethodAnnotation(ResponseStatus.class);
-                    Response wadlResponse = doResponse(mediaTypes, status);
-                    wadlMethod.getResponse().add(wadlResponse);
-                }
-                
-                
-                wadlResource.getMethodOrResource().add(wadlMethod);          
-            });
-             
-        });
-        result.getResources().add(wadlResources);
-         
-        return result;
-    }
-    
-    private Param doParam(Annotation annotation2, Class<?> paramType) {
-       Param wadlParam = null;
-       
-        if (annotation2 instanceof RequestParam ) {
-            RequestParam param = (RequestParam)annotation2;
-            
-            wadlParam = new Param();
-            QName nm = convertJavaToXMLType(paramType);
-            if (StringUtils.isNotEmpty(nm.getLocalPart())) {
-               wadlParam.setType(nm);
-            }
-            wadlParam.setName(param.value());
-            
-            
-            if (!ValueConstants.DEFAULT_NONE.equals(param.defaultValue())) {
-                String defaultValue = cleanDefault(param.defaultValue());
-                if (StringUtils.isNotEmpty(defaultValue) ) {
-                    wadlParam.setDefault(defaultValue);
-                }
-            }
-
-            wadlParam.setStyle(ParamStyle.QUERY);
-            wadlParam.setRequired(param.required());       
-        } else if (annotation2 instanceof PathVariable ) {
-            PathVariable param = (PathVariable)annotation2;
-            
-            wadlParam = new Param();                            
-            QName nm = convertJavaToXMLType(paramType);
-            if (StringUtils.isNotEmpty(nm.getLocalPart())) {
-               wadlParam.setType(nm);
-            }
-            wadlParam.setName(param.value());
-            
-            
-            wadlParam.setStyle(ParamStyle.TEMPLATE);
-            wadlParam.setRequired(true);
-        }
-        
-        return wadlParam;
-    }
-     
-    private Response doResponse(Set<MediaType> mediaTypes, ResponseStatus status) {
-       Response wadlResponse = new Response();
-        
-        mediaTypes.forEach(mediaType -> {
-            Representation wadlRepresentation = new Representation();
-            wadlRepresentation.setMediaType(mediaType.toString());
-            wadlResponse.getRepresentation().add(wadlRepresentation);
-        });
-        
-        wadlResponse.getStatus().add(getResposeValue(status));
-
-        return wadlResponse;
-    }
-    
-    private long getResposeValue(ResponseStatus status) {
-       if(status == null) {
-               return HttpStatus.OK.value();
-        } else {
-            HttpStatus httpcode = status.value();
-            return httpcode.value();
-        }
-    }
-    
-    private QName convertJavaToXMLType(Class<?> type) {
-       QName nm = new QName("");
-       String classname = type.toString();
-       classname = classname.toLowerCase();
-       
-               if (classname.indexOf("string") >= 0) {
-                       nm = new QName(NAMESPACE_URI, "string", "xs");
-               } else if (classname.indexOf("integer") >= 0) {
-                       nm = new QName(NAMESPACE_URI, "int", "xs");
-               } else if (classname.indexOf("long") >= 0) {
-                       nm = new QName(NAMESPACE_URI, "long", "xs");
-               }
-       
-       return nm;
-    }
-    
-    private Resource createOrFind(String uri, Resources wadResources) {
-         List<Resource> current = wadResources.getResource();
-         for(Resource resource:current) {
-                 if(resource.getPath().equalsIgnoreCase(uri)){
-                         return resource;
-                 }
-         }
-         Resource wadlResource = new Resource();
-         current.add(wadlResource);
-         return wadlResource;
-    }
-    
-    private String getBaseUrl(HttpServletRequest request) {
-        String requestUri = request.getRequestURI();
-        int index = requestUri.lastIndexOf('/');
-        requestUri = requestUri.substring(0, index);
-        
-        return request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + requestUri;
-    }
-     
-    private String cleanDefault(String value) {
-        value = value.replaceAll("\t", "");
-        value = value.replaceAll("\n", "");
-        return value;
-    }
-}
diff --git a/REST/web-services-spring-rest-server/src/main/resources/log4j2.xml b/REST/web-services-spring-rest-server/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/REST/web-services-spring-rest-server/src/main/resources/spring-configuration/mvc/rest/rest-config.xml b/REST/web-services-spring-rest-server/src/main/resources/spring-configuration/mvc/rest/rest-config.xml
deleted file mode 100644 (file)
index 54b8540..0000000
+++ /dev/null
@@ -1,88 +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"/>
-       
-       <!--
-               Required beans for generating XML responses from Java objects using JAXB annotations
-               Jackson also works but it doesn't generate XML with namespaces... O.o
-               
-               This implementation will be slower than the one using Jackson :( but I am going to use it just for WADL generation :)
-       -->    
-    <bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
-        <property name="packagesToScan" value="org.jvnet.ws.wadl"/>
-    </bean>
-       <bean id="jaxbConverter" class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
-       <constructor-arg ref="jaxbMarshaller" />
-       </bean>
-    
-       <!-- Required beans for generating JSON responses from Java objects -->
-    <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"/>
-               <ref bean="jaxbConverter" />
-        <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/REST/web-services-spring-rest-server/src/main/resources/spring-configuration/spring-config.xml b/REST/web-services-spring-rest-server/src/main/resources/spring-configuration/spring-config.xml
deleted file mode 100644 (file)
index e50129b..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/REST/web-services-spring-rest-server/src/main/resources/spring-configuration/spring-doc-config.xml b/REST/web-services-spring-rest-server/src/main/resources/spring-configuration/spring-doc-config.xml
deleted file mode 100644 (file)
index 773e14f..0000000
+++ /dev/null
@@ -1,31 +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-server/api-docs
-       
-       Swagger-UI:
-       http://localhost:8080/web-services-spring-rest-server/swagger-ui.html
-       
-       -->
-
-       <context:annotation-config />
-   
-       <context:component-scan base-package="de.spring.webservices.doc"/>
-       
-    <bean class="de.spring.webservices.doc.Swagger2Configuration"/>
-
-</beans>
diff --git a/REST/web-services-spring-rest-server/src/main/webapp/WEB-INF/web.xml b/REST/web-services-spring-rest-server/src/main/webapp/WEB-INF/web.xml
deleted file mode 100644 (file)
index 6c9c1d0..0000000
+++ /dev/null
@@ -1,41 +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>
-        <!-- REQUIRED PATTERN BY swagger-ui. IT DOESN'T WORK WITH ANY OTHER o.O -->
-        <url-pattern>/*</url-pattern>
-    </servlet-mapping>
-
-</web-app>
diff --git a/REST/web-services-spring-rest-server/src/test/java/de/spring/webservices/rest/controller/CarControllerIntegrationTest.java b/REST/web-services-spring-rest-server/src/test/java/de/spring/webservices/rest/controller/CarControllerIntegrationTest.java
deleted file mode 100644 (file)
index c856efb..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-package de.spring.webservices.rest.controller;
-
-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/REST/web-services-spring-rest/pom.xml b/REST/web-services-spring-rest/pom.xml
deleted file mode 100644 (file)
index e8ce3dc..0000000
+++ /dev/null
@@ -1,265 +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>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>
-       </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