02/04/2017
Introduction
Cet article vise à décrire la mise en place d’un microservice basique effectuant une recherche de document auprès de FlowerDocs.
Thèmes abordés :
- développement d’un service REST avec Spring Boot et Maven
- utilisation de l’API Web Services de FlowerDocs
Prérequis :
- Maven
- Utilisation d’un Artifactory Arondor (public ou interne)
Création du projet Maven
Cette partie fournit la configuration d’un projet Maven en incluant les dépendances nécessaires :
- Spring Boot
- Les APIs FlowerDocs
- Jackson pour la désérialisation JSON
- Slf4j pour la gestion des logs
Créer le projet Maven avec le fichier de configuration pom.xml
suivant :
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.flower.docs.samples</groupId>
<artifactId>basic-operation-hook-sample</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<spring.version>4.3.6.RELEASE</spring.version>
<spring-security.version>4.2.1.RELEASE</spring-security.version>
<spring.boot.version>1.5.1.RELEASE</spring.boot.version>
<flower.version>2.3.3</flower.version>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
<goal>build-info</goal>
</goals>
</execution>
</executions>
<configuration>
<executable>true</executable>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.flower.docs.core</groupId>
<artifactId>flower-docs-ws-client</artifactId>
<version>${flower.version}</version>
</dependency>
<dependency>
<groupId>com.flower.docs.apis</groupId>
<artifactId>flower-docs-operation-api</artifactId>
<version>${flower.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring.boot.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
</exclusion>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>
</dependencies>
</project>
Création d’une application Spring Boot
Définition de l’application Spring Boot
Définir une application SpringBoot comme celle-ci dessous :
package com.flower.samples;
@SpringBootApplication
@ComponentScan(basePackages = { "com.flower.samples", "com.flower.docs.security.authentication" })
@ImportResource({ "classpath:flower-docs-services-webservices.xml", "classpath:flower-docs-security-token.xml" })
public class SampleApplication
{
public static void main(String[] args)
{
SpringApplication.run(SampleApplication.class, args);
}
}
Configuration minimale
Dans le répertoire src/main/resources
du projet, ajouter les 2 fichiers suivant :
- application.properties, la configuration des variables de l’application Spring Boot
- log4j.xml, la configuration des logs
Configuration Spring Boot : application.properties
spring.application.name=flower-sample
security.basic.enabled=false
server.port=7777
server.contextPath=/sample
flower.password=okidoki
Configuration des logs : log4j.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration debug="false" xmlns:log4j='http://jakarta.apache.org/log4j/'>
<appender name="consoleAppender" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{ISO8601} [%t] %-5p %c - %m%n" />
</layout>
</appender>
<appender name="operation-appender" class="org.apache.log4j.RollingFileAppender">
<param name="append" value="true" />
<param name="file" value="flower-sample.log" />
<param name="maxFileSize" value="10MB" />
<param name="maxBackupIndex" value="3" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{ISO8601} [%t] %-5p %c - %m%n" />
</layout>
</appender>
<category name="com.flower">
<priority value="INFO" />
<appender-ref ref="operation-appender" />
</category>
<root>
<level value="WARN" />
<appender-ref ref="consoleAppender" />
</root>
</log4j:configuration>
Ajout d’un service REST: PingService
Afin de tester l’application, nous vous proposons d’ajouter un service REST pour tester notre application Spring Boot.
package com.flower.samples;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class PingService
{
private static final Logger LOGGER = LoggerFactory.getLogger(PingService.class);
@PostConstruct
public void initialize() throws Exception
{
LOGGER.info("{} REST service has been initialized", this.getClass().getName());
}
@RequestMapping(value = "/")
public String ping()
{
LOGGER.info("Received ping");
return "Up!";
}
}
Vous pouvez dès à présent passer à la partie Compilation & Lancement
pour tester ce nouveau service.
Rechercher un document : SampleSearchService
Essayons maintenant de développer un service REST nous permettant de rechercher un document au sein de FlowerDocs.
Authentification
La classe com.flower.docs.security.authentication.Authenticator
fournit un moyen facile d’initialiser l’authentification qui sera utilisée pour faire les appels aux web services FlowerDocs.
Grâce aux paramêtres flower.user
et flower.password
, il est possible de configurer ,grâce aux propriétés de la JVM, les informations d’authentification.
Utilisation du service de document
L’objet com.flower.docs.service.api.document.DocumentService
nous permet d’obtenir une référence au service permet la gestion des documents au sein de FlowerDocs. Il nous permet notamment de réaliser des recherches de documents.
Pour exécuter la recherche, un object com.flower.docs.domain.search.SearchRequest
est instancié à l’aide des builders :
com.flower.docs.common.search.SearchRequestBuilder
com.flower.docs.common.search.FilterClauseBuilder
com.flower.docs.common.search.CriterionBuilder
Mise en place du service REST
package com.flower.samples;
import static com.flower.docs.domain.FlowerFields.NAME;
import static com.flower.docs.domain.search.Operators.CONTAINS;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.flower.docs.common.search.CriterionBuilder;
import com.flower.docs.common.search.FilterClauseBuilder;
import com.flower.docs.common.search.SearchRequestBuilder;
import com.flower.docs.domain.exception.FunctionalException;
import com.flower.docs.domain.exception.TechnicalException;
import com.flower.docs.domain.search.Criterion;
import com.flower.docs.domain.search.SearchResponse;
import com.flower.docs.domain.search.SearchResult;
import com.flower.docs.security.authentication.Authenticator;
import com.flower.docs.service.api.document.DocumentService;
@RestController
public class SampleSearchService
{
@Autowired
private DocumentService documentService;
@Autowired
private Authenticator authenticator;
@RequestMapping(value = "/{scope}/search/{name}", method = { RequestMethod.GET })
public List<SearchResult> searchByName(@PathVariable final String scope, @PathVariable final String name)
throws FunctionalException, TechnicalException
{
authenticator.authenticate(scope);
SearchRequestBuilder requestBuilder = SearchRequestBuilder.init().max(10);
Criterion criterion = CriterionBuilder.field(NAME).operator(CONTAINS).value(name).build();
requestBuilder.filter(FilterClauseBuilder.init().criterion(criterion).build());
SearchResponse response = documentService.search(requestBuilder.build());
return response.getResults();
}
}
Compilation & Lancement
Compilation Maven
Aller à la racine du projet, puis exécuter la commande Maven suivante :
mvn clean install
Exécution du JAR
Pour démarrer le service, exécuter la commande suivante :
java -jar target/basic-operation-hook-sample-0.0.1-SNAPSHOT.jar
Pour configurer ce microservice, il est possible de passer des paramètres grâce aux propriétés de la JVM, par exemple :
java -flower.user=*** -Dflower.password=*** -Dws.url=http://localhost:8081/flower-docs-ws/services \ -jar target/basic-operation-hook-sample-0.0.1-SNAPSHOT.jar
Le JAR peut également être directement exécuté tel que
./basic-operation-hook-sample-0.0.1-SNAPSHOT.jar
Tests
Ping : si l’application démarre sans erreur, vous pouvez la tester en faisant un GET sur http://localhost:7777/sample/ et vérifier que le retour est bien Up!
avec un code de retour 200
Service de recherche : pour tester le service de recherche, vous pouvez :
- faire un GET sur http://localhost:7777/sample/Syldavia/search/a (où
Syldavia
est l’identifiant du scope FlowerDocs) - vérifier que le code de retour est
200
ainsi que les résultats remontés par la recherche au format JSON
Autres endpoints :
- GET sur
/health
retourne le statut du service - GET sur
/info
retourne les informations de build du microservice
Problèmes possibles
Connexion à FlowerDocs
Le service de ping fonctionne (GET sur /sample/
) mais un GET sur sample/<scope>/search/a
retourne :
{
"timestamp": 1493210821798,
"status": 500,
"error": "Internal Server Error",
"exception": "javax.xml.ws.soap.SOAPFaultException",
"message": "Could not send Message.",
"path": "/sample/Syldavia/search/a"
}
- Vérifier, dans vos logs (ou la console), si vous avez des exceptions type
java.net.ConnectException
- Si c’est le cas, vérifier l’URL des web services FlowerDocs utilisée
- Vous pouvez la modifier avec le paramètre
ws.url
- La valeur de cette propriété doit permettre d’accéder à la servlet exposant l’ensemble des web services SOAP du instance FlowerDocs.
- Vous pouvez la modifier avec le paramètre
Authentification FlowerDocs
Le service de ping fonctionne (GET sur /sample/
) mais un GET sur sample/<scope>/search/a
retourne :
{
"timestamp": 1493211603336,
"status": 500,
"error": "Internal Server Error",
"exception": "javax.xml.ws.soap.SOAPFaultException",
"message": "F00324: Les identifiants de l'utilisateur system ne sont pas valides",
"path": "/sample/Syldavia/search/a"
}
Vérifier la configuration du compte utilisateur utilisé dans cet exemple (cf. partie Authentification
)