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".

0
0
0
s2smodern