This article is an excerpt from MongoDB for Java Developers book which I have recently published for Packt Publishing. You will find an example Java EE application designed to run on WildFly, using MongoDB as database.

Our application will be a simple bookstore which contains a list of book titles. A start-up class will be in charge to add books to the bookstore. Once executed, the user will be able to purchase books and to perform searches over the titles.

Every application starts from a proper data schema design so our first step will be defining the database structure and then we will create the Java EE interfaces, starting with those directly involved with data CRUD and then moving out to the customer view design.

Designing the schema

Our MongoDB documents will be created in the following storage:

  • Database: javaee7
  • Collection: bookstore

And here is the list of keys we will store in our MongoDB Document:

  • id (automatically generated)
  • title (String)
  • author (String)
  • type (String)
  • price (Integer)
  • copies (Integer)

And here is an example Document that we will use in our application:

{
        "_id" : ObjectId("5541ea47438724845af4cff7"),
        "title" : "The Hobbit",
        "author" : "J.R.R. Tolkien",
        "type" : "Fantasy",
        "price" : 8,
        "copies" : 10
}

All database objects will be created by our Java Enterprise application so right now your only concern will be starting up MongoDB.

Building up the Enterprise project with NetBeans

Our Java Enterprise application will now be created, step by step. 

We will use NetBeans for coding and building our project. Our helping hand will be Maven which is a de facto standard used by Java developers to arrange for a standard application structure, compile, deploy and test it. Being an extensible framework based on plugins, the capabilities of Maven can be even expanded far beyond the above points. First of all, however, we need to configure it so that it can be used in combination with WildFly application server. Next section details it:

Configuring WildFly on NetBeans

Since the release 8.2 of Netbeans you can direclty add the WildFly server to the list of available servers, without the need to download it as a separate plugin. Start NetBeans at first. From the left side of its GUI, select the Services Tab and right-click on Server, as shown by this picture: 

wildfly jboss mongodb java enterprise

Select Add Server. The server wizard will start: as first option choose “WildFly Application Server” from the list of available application server. Click on the Next button to move ahead to the next step:

wildfly jboss mongodb java enterprise

In the following window select the location where WildFly is installed and pick up the server configuration file to be used (standalone.xml is the default configuration file):

wildfly jboss mongodb java enterprise

Click on Finish. As you can see from the following picture, now the WildFly application server is enlisted among the available Services by expanding the Servers option:

wildfly jboss mongodb java enterprise

Creating our Java Enteprise Project

In order to create our project we will use a Maven project. Maven is a popular software and release management tool which buys you:

  • A standard structure for all your Java projects
  • A centralized and automatic management of dependencies

Most development environments are Maven friendly this means that you don’t need to download any additional plugin. Choose from the File menu select New Project. Select within the Maven categories Web Application as displayed by the following window:

wildfly jboss mongodb java enterprise

Choose Next from the navigation button. The following window will be displayed:

wildfly jboss mongodb java enterprise

Enter the Project Name, its location on your file system, the GroupId, Version and Package information. Then click on Next. The Group Id in Maven terms is a naming schema used by your Maven project. It generally matches with the root package of your application

In the following window, select as Server WildFly application server and Java EE 7 Web as Java version:

wildfly jboss mongodb java enterprise

Click on Finish to create the Maven project. The following basic structure should be available in your project view:

wildfly jboss mongodb java enterprise

Within the Project Files folder a file named pom.xml has been included. This file is the Maven project’s configuration file where you will be able to configure the dependencies on other libraries and also plugins.

Maven plugins are just Java libraries which can be used to empower your Maven with additional capabilities such as compiling, deploying and testing your code

In order to compile your project you will need to specify the dependencies, that is the library which needs to be used by our project. We will start with the following set of libraries in our project:

  • Enterprise Java Beans to code a Startup class in our project
  • Java Server Faces and Context Dependency Injection to code the Web application front-end and the Back end Beans
  • Mongo DB Java Driver for storing data
  • Google’s Gson for transforming JSON Strings into Java objects and viceversa

So here is the list of Dependencies which we need to include in the pom.xml file (you can just replace this with the default one that has been created by NetBeans):

<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.wildfly.bom</groupId>
			<artifactId>jboss-javaee-7.0-with-all</artifactId>
			<version>${version.jboss.bom}</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>
<dependencies>

	<dependency>
		<groupId>org.mongodb</groupId>
		<artifactId>mongo-java-driver</artifactId>
		<version>2.12.4</version>
	</dependency>

	<dependency>
		<groupId>javax.enterprise</groupId>
		<artifactId>cdi-api</artifactId>
		<scope>provided</scope>
	</dependency>

	<dependency>
		<groupId>org.jboss.spec.javax.faces</groupId>
		<artifactId>jboss-jsf-api_2.2_spec</artifactId>
		<scope>provided</scope>
	</dependency>

	<dependency>
		<groupId>org.jboss.spec.javax.ejb</groupId>
		<artifactId>jboss-ejb-api_3.2_spec</artifactId>
		<scope>provided</scope>
	</dependency>

	<dependency>
		<groupId>org.jboss.spec.javax.annotation</groupId>
		<artifactId>jboss-annotations-api_1.2_spec</artifactId>
		<scope>provided</scope>
	</dependency>

	<dependency>
		<groupId>com.google.code.gson</groupId>
		<artifactId>gson</artifactId>
		<version>2.3.1</version>
	</dependency>

</dependencies>

You can see we have also included a Bill of Materials (BOM) at the top of our dependencies. This is an handy option so that you don’t need to specify each of WildFly’s library version, as they are maintained in the external BOM file

We are done with the Project’s skeleton. Now for the real classes which will make up your application.


The first Java class we will add is named Book and will be used to map MongoDB documents. It contains the same field as the corresponding keys of the document.

package com.packtpub.mongo.chapter4.bean;

public class Book {
 
	String title;
	String author;
	String type;
	int price;
	int copies;

	public Book() { }

	public Book(String title, String author, String type, int price) {
		super();
		this.title = title;
		this.author = author;
		this.type = type;
		this.price = price;
		this.copies = 10;
	}

// Getter and Setters omitted for brevity
}

Now that we have the basic structure to host Mongo documents we need to handle the connection toward MongoDB. Within the Java Enterprise environment there is a better alternative than the following piece of your code around your classes:

MongoClient mongoClient = new MongoClient("localhost", 27017);

Instead of the above, we will create a CDI Producer which will be in charge to create an instance of the MongoClient object and share it with the classes of your application. So add a class named Producer to your project:

package com.packtpub.mongo.chapter4.producer;

public class Producer {
	  @Produces
	  public MongoClient mongoClient() {
	    try {
			return new MongoClient("localhost", 27017);
		} catch (UnknownHostException e) {
			e.printStackTrace();
		}
	    return null;
	  }
}

Producers are an useful addition provided by CDI which can be used when the concrete type of the objects to be injected may vary at runtime or when the objects require some custom initialization that is not performed by the bean constructor

Now we will add the Controller class named BookStore, which receives input from the User Interface and constructs the list of available books:

package com.packtpub.mongo.chapter4.controller;

@Model
public class BookStore implements Serializable {

	@Inject
	MongoClient mongoClient;

	List<Book> listBooks;
	
	String filter;

	@PostConstruct
	private void init() {
		doQuery();
	}

	public void doQuery() {
		listBooks = query();
	}
	public List<Book> query() {
		Gson gson = new Gson();

		DB db = mongoClient.getDB("javaee7");

		DBCollection coll = db.getCollection("bookstore");
		DBCursor cursor = null;
		if (filter == null || filter.trim().length() == 0) {
			cursor = coll.find();	
		}
		else {
			BasicDBObject q = new BasicDBObject();
			q.put("title",  java.util.regex.Pattern.compile(filter));
			cursor = coll.find(q);
		}
		
		
		List<Book> list = new ArrayList();
		try {
			while (cursor.hasNext()) {
				DBObject obj = cursor.next();

				list.add(gson.fromJson(obj.toString(), Book.class));

			}
		} finally {
			cursor.close();
		}
		return list;
	}

	public void buy(Book book) {

		Gson gson = new Gson();

		int copiesLeft = book.getCopies() - 1;
		DB db = mongoClient.getDB("javaee7");

		DBCollection coll = db.getCollection("bookstore");

		BasicDBObject newDocument = new BasicDBObject();
		newDocument.append("$set",
				new BasicDBObject().append("copies", copiesLeft));

		DBObject searchQuery = (DBObject) JSON.parse(gson.toJson(book));
		coll.update(searchQuery, newDocument);

		listBooks = query();

	}

 
}

And now let’s discuss about the most relevant parts of this class: first of all, there is a @Model annotation at the top of it. This is a CDI stereotype which can be used on CDI beans in order to achieve two things:

  • Defines a Request Scope for the class. It means that the class will be created and destroyed according to the user’s request lifecycle
  • Guarantees Expression Language visibility. It means that the class can be used in our UI

Next, we are using the @Inject annotation to let the container provide an instance of the MongoClient class which is actually done by the Producer class we have just coded.

The query and buy methods are our business methods which are respectively used for listing the books and for purchasing them. If you have gone through the Gson section in the previous chapter this code should be quite intuitive for you. Within the query method you will find a search expression which is used to filter among the titles using a Regular Expression pattern. The purpose of this block of code is to provide a SQL LIKE functionality during the search

BasicDBObject q = new BasicDBObject();

q.put("title",  java.util.regex.Pattern.compile(filter));

cursor = coll.find(q);

The list of available books is ultimately maintained into the List<Book> listBooks collection which is updated every time a book is purchased. The above two classes are sufficient to make up the backbone of a Java EE application. We will include one more class to provide some available books when the application is deployed:

package com.packtpub.mongo.chapter4.ejb;

@Singleton
@Startup

public class SchemaSetup {
	@Inject
	MongoClient mongoClient;

	@PostConstruct
	public void createSchema() {
		try {

			DB db = mongoClient.getDB("javaee7");

			DBCollection coll = db.getCollection("bookstore");
			coll.drop();
			coll = db.getCollection("bookstore");

			Book[] book = new Book[5];
			book[0] = new Book("A Tale Of Two Cities", "Charles Dickens","Novel", 10);
			book[1] = new Book("Le Petit Prince", "Antoine de Saint-Exupery","Novel", 8);
			book[2] = new Book("The Da Vinci Code", "Dan Brown", "thriller", 12);
			book[3] = new Book("Think and Grow Rich", "Napoleon Hill","Motivational", 10);
			book[4] = new Book("The Hobbit", "J.R.R. Tolkien", "Fantasy", 8);
			Gson gson = new Gson();

			for (Book b : book) {
				DBObject obj = (DBObject) JSON.parse(gson.toJson(b));
				coll.insert(obj);
			}

		} catch (Exception e) {
			System.err.println(e.getClass().getName() + ": " + e.getMessage());
		}
	}
}

The above class is a Singleton EJB which means that only one instance of this class will be created by the container. Thanks to the @Startup annotation, the createSchema  method, which is annotated with @PostConstruct, will be executed when the application is deployed. 

Inside the createSchema method we first clean up our existing Collection of books and then we create a new Collection by using a combination of MongoDB Driver and Google Gson API.

The server side part is completed. We need one view for displaying the book titles and a couple of buttons to perform respectively a filter on the titles and to purchase a book. Following here is the index.xhtml page which needs to be added to the Project’s Web pages:

<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:c="http://java.sun.com/jsp/jstl/core">
 <h:head></h:head>
 
<h:body>

	<h:form id="bookstore">
		<h:panelGrid >
			<h:outputLabel value="Filter title: " style="font-weight:bold" />
			<h:inputText value="#{bookStore.filter}" />
			<h:commandButton actionListener="#{bookStore.doQuery}" styleClass="buttons" value="Search" />
			<h:dataTable value="#{bookStore.listBooks}" var="item" styleClass="table"
				headerClass="table-header"
				rowClasses="table-odd-row,table-even-row">
				<h:column>
					<f:facet name="header">Title</f:facet>
					<h:outputText value="#{item.title}" />
				</h:column>
				<h:column>
					<f:facet name="header">Author</f:facet>
					<h:outputText value="#{item.author}" />
				</h:column>

				<h:column>
					<f:facet name="header">Price</f:facet>
					<h:outputText value="#{item.price}" />
				</h:column>
				<h:column>
					<f:facet name="header">Type</f:facet>
					<h:outputText value="#{item.type}" />
				</h:column>
				<h:column>
					<f:facet name="header">Copies</f:facet>
					<h:outputText   value="#{item.copies}"/>
				</h:column>						

				<h:column>
					<f:facet name="header">Buy</f:facet>
				   <h:commandButton actionListener="#{bookStore.buy(item)}" rendered="#{item.copies > 0}"
						styleClass="buttons" value="Buy" />
				</h:column>							
			</h:dataTable>		 
		</h:panelGrid>

	</h:form>

</h:body>
</html>

The above code contains a few basic JSF components such as an itemText which is an HTML text field used to perform a filter over the title field. The next component is a dataTable that is used to display tabular data contained in the BookStore’s listBooks ArrayList. Within the dataTable every field is referenced through the variable “item” so that we have a tabular view of all our BookStore.

Finally, a Buy button is included which submits the execution to the buy method of the BookStore Bean, passing as argument the item on which the button was clicked.

Just to remind you, the BookStore beans can be referenced from the User Interface as we have tagged it with the @Model annotation. As no specific name has been chosen for this Bean, it will be referenced using its default EL name which is ""bookStore".


Compiling and deploying the project is just one click away from you, provided that you have added a WildFly application server to your list of Services. Simply right-click on your project and choose “Run”. A sequence of operations will be triggered:

1. At first WildFly application server will start

2. The Web application will be deployed

3. The index.xhtml page will be displayed

If you are not using NetBeans, simply follow the next section which will detail a generic compilation and deployment procedure that can be used from the shell prompt or wrapped by your Development Environment

Compiling and deploying from the shell

Any Maven project can be compiled and packaged by executing the following goals:

mvn clean install

This will generate an artifact named javaee7-mongodb.war which needs to be deployed on the application server.  The simplest way to do it, is copying the file into the standalone/deployments folder of WildFly.

If you want to automate the distribution of the Web application, we would suggest rather adding Maven’s WildFly plugin which will handle the deployment for you. In order to do that, you need to add the following plugin definition at the bottom of your pom.xml file:

<build>
	<finalName>${project.artifactId}</finalName>
	<plugins>
		<plugin>
			<groupId>org.wildfly.plugins</groupId>
			<artifactId>wildfly-maven-plugin</artifactId>
			<version>1.0.2.Final</version>
		</plugin>
	</plugins>
</build>

 Now with the plugin in place, you can perform compilation, packaging and deployment with a single command:

mvn clean install wildfly:deploy

 A successful execution will terminate with an output like the following one:

INFO: JBoss Remoting version 4.0.3.Final
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 12.269 s
[INFO] Finished at: 2015-04-30T10:39:35+01:00
[INFO] Final Memory: 14M/37M
[INFO] ------------------------------------------------------------------------

Running the application

Whatever is your development environment, you will end up with the Web application deployed on WildFly. So now browse on over the following URL in order to test the application: http://localhost:8080/javaee7-mongodb/index.xhtml

Here is how your application should look like (We have omitted to include the stylesheets used in the index.xhtml page for the sake of brevity. You can find the complete source code of the book in the download area)

wildfly jboss mongodb java enterprise

You can try how the application works by clicking on the “Buy” button which will decrease the count of available book copies. Entering some text into the “Filter title” field and clicking on “Search” will restrict the search only to titles containing that text.

Java MongoDB

      MongoDB for Java Developers

  • A step-by-step tutorial to create leaner and faster applications using MongoDB
  • Reuse the skills you have acquired through Hibernate or Spring to promote your applications to use NoSQL storage
  • Explore the list of libraries that are already available to assist you in developing Java EE applications with MongoDB
0
0
0
s2smodern