Java EE 7 Movieplex is a standard multi-tier enterprise application that shows design patterns and anti-patterns for a typical Java EE 7 application.
This section explains how this application can be deployed in a Docker container using a pre-built WAR in two different ways:
-
Using in-memory database in WildFly
-
Using container linking to link WildFly and MySQL database
And then it will cover how to test such applications.
Pull the Docker image that contains WildFly and pre-built Java EE 7 application WAR file as shown:
docker pull arungupta/javaee7-hol
The javaee7-hol Dockerfile is based on jboss/wildfly
and adds the movieplex7 application as war file.
Run it:
docker run -it -p 8080:8080 arungupta/javaee7-hol
See the application in action at http://dockerhost:8080/movieplex7/. The output is shown:
This uses an in-memory database with WildFly application server as shown in the image:
Only two changes are required to the standard jboss/wildfly
image:
-
By default, WildFly starts in Web platform. This Java EE 7 application uses some capabilities from the Full Platform and so WildFly is started in that mode instead as:
CMD ["/opt/jboss/wildfly/bin/standalone.sh", "-c", "standalone-full.xml", "-b", "0.0.0.0"]
-
WAR file is copied to the
standalone/deployments
directory as:RUN curl -L https://github.com/javaee-samples/javaee7-hol/raw/master/solution/movieplex7-1.0-SNAPSHOT.war -o /opt/jboss/wildfly/standalone/deployments/movieplex7-1.0-SNAPSHOT.war
Deploy Java EE 7 Application explained how to use an in-memory database with the application server. This gets you started rather quickly but becomes a bottleneck soon as the database is only in-memory. This means that any changes made to your schema and data are lost when the application server shuts down. In this case, you need to use a database server that resides outside the application server. For example, MySQL as the database server and WildFly as the application server.
This section will show how Docker Container Linking can be used to connect to a service running inside a Docker container via a network port.
-
Start MySQL server as:
docker run --name mysqldb -e MYSQL_USER=mysql -e MYSQL_PASSWORD=mysql -e MYSQL_DATABASE=sample -e MYSQL_ROOT_PASSWORD=supersecret -p 3306:3306 -d mysql
-e
define environment variables that are read by the database at startup and allow us to access the database with this user and password. -
Start WildFly and deploy Java EE 7 application as:
docker run -it --name mywildfly --link mysqldb:db -p 8080:8080 arungupta/wildfly-mysql-javaee7
--link
takes two parameters - first is name of the container we’re linking to and second is the alias for the link name.NoteContainer LinkingCreating a link between two containers creates a conduit between a source container and a target container and securely transfer information about source container to target container.
In our case, target container (WildFly) can see information about source container (MySQL). When containers are linked, information about a source container can be sent to a recipient container. This allows the recipient to see selected data describing aspects of the source container. For example, IP address of MySQL server is expoed at $DB_PORT_3306_TCP_ADDR and port of MySQL server is exposed at $DB_PORT_3306_TCP_PORT. These are then used to create the JDBC resource.
See more about container communication on the Docker website Linking Containers Together
-
See the output as:
> curl http://dockerhost:8080/employees/resources/employees <?xml version="1.0" encoding="UTF-8" standalone="yes"?><collection><employee><id>1</id><name>Penny</name></employee><employee><id>2</id><name>Sheldon</name></employee><employee><id>3</id><name>Amy</name></employee><employee><id>4</id><name>Leonard</name></employee><employee><id>5</id><name>Bernadette</name></employee><employee><id>6</id><name>Raj</name></employee><employee><id>7</id><name>Howard</name></employee><employee><id>8</id><name>Priya</name></employee></collection>
Testing Java EE applications is a very important aspect. Especially when it comes to in-container tests, JBoss Arquillian is well known to make this very easy for Java EE application servers. Picking up where unit tests leave off, Arquillian handles all the plumbing of container management, deployment and framework initialization so you can focus on the task at hand, writing your tests.
With Arquillian, you can use WildFly remote container adapter and connect to any WildFly instance running in a Docker container. But this wouldn’t help with the Docker container lifycycle management.
Arquillian Cube, an extension of Arquillian, allows you to control the lifecycle of Docker images as part of the test lifecyle, either automatically or manually. This extension allows to start a Docker container with a server installed, deploy the required deployable file within it and execute Arquillian tests.
The key point here is that if Docker is used as deployable platform in production, your tests are executed in a the same container as it will be in production, so your tests are even more real than before.
-
Check out the workspace:
git clone http://github.com/javaee-samples/javaee-arquillian-cube
-
Edit
src/test/resources/arquillian.xml
file and change the IP address specified inserverUri
property value to point to your Docker host’s IP. This can be found out as:docker-machine ip lab
-
Run the tests as:
mvn test
This will create a container using the image defined in
src/test/resources/wildfly/Dockerfile
. The container qualifier inarquillian.xml
defines the directory name insrc/test/resources
directory.NoteA pre-built image can be used by specifying:
wildfly: image: jboss/wildfly
instead of
wildfly: buildImage: dockerfileLocation: src/test/resources/wildfly
By default, the “cube” profile is activated and this includes all the required dependencies.
The result is shown as:
Running org.javaee7.sample.PersonDatabaseTest Jun 16, 2015 9:23:04 AM org.jboss.arquillian.container.impl.MapObject populate WARNING: Configuration contain properties not supported by the backing object org.jboss.as.arquillian.container.remote.RemoteContainerConfiguration Unused property entries: {target=wildfly:8.1.0.Final:remote} Supported property names: [managementAddress, password, managementPort, managementProtocol, username] Jun 16, 2015 9:23:13 AM org.xnio.Xnio <clinit> INFO: XNIO version 3.2.0.Beta4 Jun 16, 2015 9:23:13 AM org.xnio.nio.NioXnio <clinit> INFO: XNIO NIO Implementation Version 3.2.0.Beta4 Jun 16, 2015 9:23:13 AM org.jboss.remoting3.EndpointImpl <clinit> INFO: JBoss Remoting version (unknown) Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 16.406 sec - in org.javaee7.sample.PersonDatabaseTest Results : Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------
-
In
arquillian.xml
, add the following property:<property name="connectionMode">STARTORCONNECT</property>
This bypasses the create/start Cube commands if a Docker Container with the same name is already running on the target system.
This allows you to prestart the containers manually during development and just connect to them to avoid the extra cost of starting the Docker Containers for each test run. This assumes you are not changing the actual definition of the Docker Container itself.