- Author: Sébastien Mosser
- Version: 0.9
- Build: Maven (3)
- Language: Java (8)
- Deployment: OSGi components on top of Apache Service Mix (6.0.0)
- Test: SoapUI (5.2.0) / JUnit (4.12)
We provide here a way to create generators used to uniquely identify objects. We will expose a set of generators as the initial resource available in the system, and the user will be able to:
- Available set of generators:
/generators
POST
is used to create a new generator
- Given generator:
/generator/{name}
DELETE
is used to remove this generatorGET
is used to retrieve a new generated value for this generator
The first steps are dedicated to the setup of a Maven environment, and the implementation of the service.
We are using Maven to support the build. Here is the structure of a valid Maven project:
azrael:rest mosser$ tree .
.
├── pom.xml
├── src
│ └── main
│ ├── java
│ └── fr.unice.polytech.al.drones.central.resources
└── test
- The
pom.xml
file describes the project - The
src/main/java
directory contains the source code of the service - The
src/main/fr.unice.polytech.al.drones.central.resources
directory contains additional fr.unice.polytech.al.drones.central.resources - The
test
directory contains the unit testing source code for the service
The Project Object Model (POM) describes the service, its dependencies and how to build it. The important attributes are:
groupId
&artifactId
: pair of unique names used to identify the service in the Maven dependency system;name
: the name ServiceMix will display when listing componentspackaging
: we are building an OSGibundle
, not a classical JAR file;dependencies
: we rely on 2 artefacts from CXF:org.apache.servicemix.specs.jsr339-api-2.0
to access to the JAX-RS specification (e.g., REST for java)org.apache.servicemix.bundles.commons-httpclient
to work with the HTTP protocol- We also import the classical
org.json
library to build JSON representations.
build
/maven-bundle-plugin
: this plugin adapts the build process to create an OSGi bundle. The important attributes are the following:Bundle-SymbolicName
: the name that ServiceMix will uses to identify the component;Export-Package
: the Java packages exported by the components and available for others OSGi components.Embed-Dependency
andEmbed-Transitive
will include in our bundle all the dependencies used by the project. This is a quick and dirty hack to importorg.json
, it is preferable to use a library available as an OSGi dependency.
We provide here a way to create generators used to uniquely identify objects. We will expose a set of generators as the initial resource available in the system, and the user will be able to:
- Available set of generators:
/generators
POST
is used to create a new generatorGET
is used to retrieve the existing generators
- Given generator:
/generator/{name}
DELETE
is used to remove this generatorGET
is used to retrieve a new generated value for this generator
In this course, we are not interested by the contents of the operations. Mocks will always be preferred to complex implementations.
We consider a Generator as a public name and a private counter, which will generate identifiers like {name}{cpt}
and incrementing cpt after each generation.
We create a quick'n dirty Storage
class that will act as a storage backend for the very purpose of this cookbook. It contains a static hashmap that will be the storage layer, and 3 methods (create
, read
and delete
) of the classical CRUD pattern. We also add a findAll
method to retrieve all the elements in the database at once. Using a static
block, we add a generator in the system for demonstration purpose.
Each entry in the public API described previously is implemented as a method in the GeneratorService
class. The important annotations are:
@Path
to identify where a resource will be exposed@Consumes
to specify which kind of input is expected (a media type)@Produces
to specify which kind of output is produced (a media type)@GET
,@POST
and@DELETE
to expose methods as operation available through the uniform HTTP API.
Considering the implemented service, we need to make it compliant with the OSGi standard, and then package it before deploying it on top of our ESB.
In the fr.unice.polytech.al.drones.central.resources
directory, we rely on a file named OSGI-INF/blueprint/blueprint.xml
that describes the service as an OSGi component. This file describes where the service will be deployed (here under a demo
URL prefix), and bind this exposition to the implementation class through the definition of a bean.
<jaxrs:server id="genService" address="/demo">
<jaxrs:serviceBeans>
<ref component-id="genSvc"/>
</jaxrs:serviceBeans>
</jaxrs:server>
<bean id="genSvc" class="GeneratorService"/>
Let's rely on maven black magic: mvn clean package
. The command produces in the target
directory a JAR file that contains our bundle. The name of the file is based on the artifactId
and version
attributes, here ws-rest-1.0.jar
.
We consider here an up and running instance of ServiceMix (if not, install ServiceMix on your computer, and start it by running the bin/servicemix
script.
azrael:bin mosser$ ./servicemix
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=256M; support was removed in 8.0
Please wait while Apache ServiceMix is starting...
100% [========================================================================]
Karaf started in 10s. Bundle stats: 233 active, 233 total
____ _ __ __ _
/ ___| ___ _ ____ _(_) ___ ___| \/ (_)_ __
\___ \ / _ \ '__\ \ / / |/ __/ _ \ |\/| | \ \/ /
___) | __/ | \ V /| | (_| __/ | | | |> <
|____/ \___|_| \_/ |_|\___\___|_| |_|_/_/\_\
Apache ServiceMix (6.0.0)
Hit '<tab>' for a list of available commands
and '[cmd] --help' for help on a specific command.
Hit '<ctrl-d>' or 'osgi:shutdown' to shutdown ServiceMix.
karaf@root>
To deploy the component, copy-paste the JAR file into the deploy
directory of your local service mix instance. It triggers the hot deployment process available on the bus (look at the log file data/log/servicemix.log
).
The bundle:list
command of the ServiceMix shell lists all the bundles known by the bus, including our new one at the bottom of the list:
karaf@root>bundle:list
START LEVEL 100 , List Threshold: 50
ID | State | Lvl | Version | Name
----------------------------------------------------------------------------------------------------
...
238 | Active | 80 | 1.0 | SOA1 :: REST-based implementation
This commands tells us that our bundle is deployed under the id 234
. This key will be used by other commands to control its lifecycle:
bundle:stop 238
: to stop the bundlebundle:start 238
: to start the bundle againbundle:uninstall 238
: to uninstall the bundle (removing it completely from ServiceMix). This can also be done by removing the jar file from thedeploy
directory.
Remark: an uninstalled bundle cannot be re-installed with the hot-deployment feature as is. Recreating the JAR is the most simple way to benefit from the hot deployment again,
Web services deployed on top of ServiceMix are available under the cxf
url prefix, through an HTTP server deployed on port 8181.
We exposed the service using the demo
URL prefix, and the initial resource is generators
. Thus, our service is available at the following URL:
azrael:rest mosser$ curl -w "\n" http://localhost:8181/cxf/demo/generators/
["demogen"]
Service can (must?) be unit tested as classical code, from an internal point of view. Maven expects the JUnit test code to be under the test/java
directory. Actually, unit testing should have been done before the deployment phase.
We consider here an up and running installation of SoapUI (Open-source version). Create a new REST Project, select _Import WADL...` option and give the url of the WADL contract of your service (http://localhost:8181/cxf/demo?_wadl).
Remark: WADL was supposed to be the REST equivalent of WSDL/SOAP. Actually no one really use it anymore (or never used it at all), contrarily to WSDL that is a de facto standard on the SOAP universe.
SoapUI generates a set of test request for each operation exposed in the service, and you can use it to interact with your system.