JavaEE with MongoDB and Morphia

View on GitHub

by Ulrich Cech

Einleitung

MongoDB is an open-source, document database designed for ease of development and scaling. I don't want to recap all the key features of MongoDB here, must of the readers perhaps always know MongoDB, but for the one, who don't know anything about MongoDB, I suggest a shot introduction from the official MongoDB-documentation found here:
https://docs.mongodb.com/manual/introduction/

There are already many articles and tutorials about the MongoDB-Java-Driver, but in this article, I want to step a bit further and show, how to basically design and implement a JavaEE Web-Application with MongoDB. For the persistence layer, we will use Morphia as an entity-mapper, which as very closely designed to the JPA-standard (you will be familiar with several annotation names).

I don't want to show the typical "Hello world"-examples. I want to show you real-world scenarios, especially in case of the business objects. In addition, I want to build an architecture, that you can adopt 1-on-1 to real and productive business applications. For that, we want to implement a simple ordering-system which has users, products and orders. You will find the complete source code on my GitHub-account:
https://github.com/UlrichCech/javaee-mongo-morphia (use the GIT-Tag part_1)

The only requirement is a current IDE with a configured JavaEE7-conform server (like Payara, Glassfish, Wildfly). I personally prefer Payara, because it is based on the reference implementation for JavaEE, namely Glassfish, and the Payara-team takes a lot of effort to extend it, update the libraries and make bugfixes with a quarterly update-cycle. If you look at the Github-repository of the Payara-team https://github.com/payara, you see plenty of commits (I think, they work 24 hours a day :-)).

Motivation

Especially with new projects you want to be productive quickly and achieve fast results. Traditionally in a JavaEE-environment, you will use JPA in the persistence layer, combined with a relational database. I will demonstrate how well MongoDB integrates into a JavaEE environment in conjunction with Morphia. It is intended to go especially to a certain 'elegance' and simplicity of the technologies.

Typically, a SQL database server must be installed and configured, then you have to deal with the configuration of the Datasource and finally you must establish the connection via the persistence.xml in the application.

In your traditional JavaEE-application design, you start to consider, how the business entities can be mapped to the individual tables and how their relationships are modeled. And exactly at this point, the problems get started, because a good domain driven design is very difficult to map to the relational model. Due to the distribution of data across a number of tables that are somewhat related (relational database model) we must always deal and think of transaction, because every update to the data involves always multiple tables, which must be updated in parallel. And there is a potential possibility, that another client wants to update a part of the same data at the same time.

MongoDB goes one step further and does not offer transactions because transactions in most cases are actually not needed and are mainly needed in the 'relational world' because of the distribution of data across multiple tables. But in MongoDB we have a single "document" (perhaps with embedded sub-documents), which is considered as a complete unit and is persisted as this complete unit in one collection. So it cannot happen that an embedded sub-document (which would be stored in a relational model in another table), is used or updated by another process or user. There would be always the complete document, which is handled and updated as a unit and always the complete document will be saved or updated in the collection. So, the document itself is always consistent. This makes the developers' life much easier. Of course, different users can access or update one document as a whole in parallel, but the document will always be consistent and updated in a consistent way. If there is a conflict (because the current document is meanwhile updated by an other user), this situation can be identified via a special field of the entity, which is annotated with @org.mongodb.morphia.annotations.Version. It is the same behaviour as with JPA and provides a kind of optimistic locking. This conflict must be handled by the application, and the same is true for the relational model. But with the document centric approach, the possibility for a conflict is minimized and much easier to handle then in the old relational world.

But sometimes, you really need the concept of a transaction. Then you can stick with the so called "Two phase commit", which is described in very detail here:
https://docs.mongodb.com/manual/tutorial/perform-two-phase-commits/

Domain-Driven-Design

Basically the Domain Driven Design is understood to provide the business domain stand in the foreground. Until now, we always almost did quite some work with normalizing the database to reduce data duplication.

Example: A user has properties like a lastname, a firstname, age, username, password, birthdate. Mostly, the user has an address, too. And in a shop system, he needs a credit card or a bank account to make an order. If we use normalization, it will look like this:
User → Address
User → paymentMethod ← All-PaymentMethods

Let's go one step further. In a shop system, every user has 0-n orders with 1-n articles/products:

User → Order → orderedArticles ← articles

Between orders and articles, we have a m:n-relation, one order can have multiple articles, and one article can be chosen in many orders. So in the relational model, we need 3 tables here.

In a real shop-application, we cannot do this with a complete normalized database concept because if we only refer to the article, any change to the price of this article would be used for every reference. So if we want to know the total sum of a specific recent order, we will get different result with every change to a price of an article. We would always get the current price, not the price, when the user ordered this article. So, at this point, we have to break the normalization and store the price at the time of the order. Normally, we need to store the description as well to the order, so that in case of some complaint, we need to see the conditions for this article exactly to the time of the order. So we must store information redundantly for traceability and embed the articles to the order. When we embed these articles, the fields of the articles are 'copied' into the order table or into a corresponding table of 'ordered articles', when we model a 1:n-relation like this:
Order -> OrderedArticles

Another option could be to store only the changes, which are made at the article, as a kind of history, and if we need the state of the article to a special time, you have to reconstruct it with the information of the historical changes. But such history is not trivial to implement, especially with hierarchical structured entity.

Ok, let's look at the implementation for the order process. We have to store information to several tables, which of course must be done in a transactional way in order to have a consistent state of our order. It makes no sense to store the main order information but without the ordered articles. So all tables have to be updates/inserted together.

But, if we now look at the domain-model, it would know nothing of the various tables. It is one object with a list of ordered articles and the user, who has ordered these articles. This business object of such an order could be modelled as:

class Order {
   private String orderNo;
   private Date orderDate;
   private User user;
   private List<Article> articles;

   public BigDecimal calculatePrice() {
       BigDecimal sum = BigDecimal.ZERO;
       for (Article article : articles) {
           sum.add(article.getBruttoPrice());
       }
   }
}
class Article {
    private BigDecimal price;
    private double vat;

    public BigDecimal getBruttoPrice() {
        // TODO: calculate brutto;
    }
}

This looks very similar to the JPA-structure, but we will see the the main difference or the advantage of MongoDB a bit later. In JPA, we would probably use @ManyToOne for the reference to the user, and an @Embedded für the list of articles.

The attentive reader will have noticed, that there is a business method, namely the calculatePrice() method in the Order class. A classical JPA-object is usually an anaemic data container, a DTO with properties and only getter- and setter-methods. In a domain driven design, there are mostly rich-domain objects. 'Rich' in term of having additional business specific methods. In our example, the order knows best about its total price. So the method for calculating this total price would go into the `Order' class. You can image, what other methods could also go here, perhaps calculating taxes or something like this.

In the typical and classical JPA-way, you would model the 'Order'-object the following way:

@javax.persistence.Entity
class Order {
   private String orderNo;

   @Temporal(TemporalType.Date)
   private Date orderDate;

   @javax.persistence.Embedded
   private de.sofiworx.examples.jmm.business.user.entity.Address address;

   @OneToMany
   private List<OrderedArtikel> articles;

   // getter and setter
}

Here we see the next big disadvantage of the relational database model: If we embed objects (in our case the address-object) and we change the address object (eg. add a new field), we always have to make a schema update. If we embed an @Entity we must update two tables, namely the table of the Entity and the table, where we embed this entity as well. MongoDB is schema-less, and that's a big advantage and give us a great performance hit through better productivity, because we do not have to make updates to the database, if we add some field to an object.

In summary: in the embedded scenario, where we want to add one more field to the embedded object, we need two schema updates to the relational database. Very un-productive, isn't it? in MongoDB, we do not need an update at all. Sure, it needs a bit of careful development here, because you don't want to deal with a hugh amount of different 'object versions', which all will have different amount of property. This would be a nightmare in the application code to handle every version of our entities. But if you have this in mind, the schema-less paradigm is a hugh productivity goal.

After this short introduction, we want to get started hacking. First, we will install our MongoDB, start the mongod-process (that's the MongoDB server deamon) and then we want to persist our first object into MongoDB. Let's go with hands-on-doing.

Setup a MongoDB database server

The first main advantage of MongoDB is its easy setup. There is no complicated installation process, just download the archive file, extract it and start the database-deamon:

  1. Download the newest MongoDB from https://www.mongodb.org/downloads#production
  2. use the archive file appropriate for your operating system
  3. Extract the file to directory, e.g. /work/database/mongodb
  4. create the data directory mkdir /work/database/mongodb/data
  5. on to the commandline type: /work/database/mongodb/mongod -dbpath=data

That's it. Now you have a MongoDB server running, on localhost with port 27017 (this is MongoDB-default).

I will omit dealing with the Mongo-Client in Terminal window, create databases and collections and so on. Please refer to the official documentation of MongoDB and their tutorials for further information:
https://docs.mongodb.com/manual/

Now, that we have the MongoDB-Server running, we want to connect to it from our application. So it is time to setup our application and start coding.

We will start with a plain and clean Maven project, which can be used in every IDE of your choice. Start a new Maven-Project and use the following pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<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>de.sofiworx.examples</groupId>
    <artifactId>javaee-mongo-morphia</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <failOnMissingWebXml>false</failOnMissingWebXml>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>7.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <finalName>javaee-mongo-morphia</finalName>

        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <excludes>
                    <exclude>assemblies/**</exclude>
                </excludes>
                <filtering>true</filtering>
            </resource>
        </resources>

        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>${maven.compiler.source}</source>
                    <target>${maven.compiler.target}</target>
                    <compilerVersion>${maven.compiler.source}</compilerVersion>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.6</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

We only need dependency for JavaEE, for sure, and provide some basic plugins for compiling and building a WAR-file.

For connecting to MongoDB and using Morphia as an object-mapper, we need two more dependencies. The first one is the dependency for the MongoDB-Java-Driver and the second one is Morphia:

...
<dependency>
    <groupId>org.mongodb</groupId>
    <artifactId>mongo-java-driver</artifactId>
    <version>3.2.2</version>
</dependency>
<dependency>
    <groupId>org.mongodb.morphia</groupId>
    <artifactId>morphia</artifactId>
    <version>1.2.0</version>
</dependency>
...

For the implementation, first we need a connection to our database. This connection is provided by the MongoDB-Java-Driver, which is comparable with the JDBC-driver. You can find more about the MongoDB Java Driver here:
https://github.com/mongodb/mongo-java-driver But we neither use JPA nor some kind of Datasources and no persistence.xml, we implement our 'EntityManager' on our own:

public class DBConnection {
    private static MongoClient mongo;

    public DBConnection() {
    }

    public void init() {
        if (mongo == null) {
            mongo = new MongoClient("localhost", 27017);
        }
    }

    public void closeConnection() {
        if (mongo != null) {
            mongo.close();
            mongo = null;
        }
    }
}

If we instantiate the DBConnection class and call its init()-method, we see some log output like this:

INFORMATION: Monitor thread successfully connected to server with description ServerDescription{address=localhost:27017,
 type=STANDALONE, state=CONNECTED, ok=true, version=ServerVersion{versionList=[3, 2, 6]}, minWireVersion=0, maxWireVersion=4,
 maxDocumentSize=16777216, roundTripTimeNanos=1514197}

=> Now we have a client connection to our MongoDB database.

Ok, we extend our example and want to persist our first object. For that, we use a simple and small JUnit-test case, where we implement the persisting of an object into the database:

public class DBConnectionTest {

    @Test
    public void persistSimpleDocument() {
        DBConnection dbConnection = new DBConnection();
        dbConnection.init();
        final MongoClient mongoClient = dbConnection.getMongoClient();
        final MongoCollection<Document> testdataCollection =
                mongoClient.getDatabase("jmm").getCollection("testdata");
        try {
            Document storeDocument = new Document();
            storeDocument.put("field1", "value1");
            storeDocument.put("field2", "value2");
            storeDocument.put("field3", "value3");
            testdataCollection.insertOne(storeDocument);
            assertThat(testdataCollection.count(), is(1L));
            final Document retrievedDocument =
                    mongoClient.getDatabase("jmm").getCollection("testdata")
                            .find().first();
            assertThat(retrievedDocument.containsKey("field2"), is(true));
            System.out.println(retrievedDocument.toJson());
            testdataCollection.deleteOne(retrievedDocument);
            assertThat(testdataCollection.count(), is(0L));
        } finally {
             // completely clear the collection after test-execution
            testdataCollection.deleteMany(new BsonDocument());
        }
    }
}

MongoDB has collections (which are somewhat comparable to the tables of a SQL database). Every entry in these collections is a document, and these documents consists of key-value-entries. A value can of course be again a document (then we name this a sub-documents), so we can model really complex and hierarchical objects, which are stored as one document into one collection.

Ok, in this example, we put one document into the database and retrieved one document, so we can compare these two documents for equality. The document is finally printed out in JSON-format and should look like:

{ "_id" : { "$oid" : "57378c84ad595366d626540f" },
  "field1" : "value1",
  "field2" : "value2",
  "field3" : "value3"
}

For more examples of the MongoDB-JavaDriver, please refer to the following quick-tour:
http://mongodb.github.io/mongo-java-driver/3.0/driver/getting-started/quick-tour/

Morphia

The MongoDB-Java driver provides us a good interface to the MongoDB database. The key-value-structure can easily be mapped to a simple Java-Map, so we have a really good known paradigm at hand to work with MongoDB.

But, of course, we don't want to map every single property of our business objects on our own. We want to have some mapping tool or library, like an object-relational-mapper (ORM) in the JPA world. And here comes Morphia into play.

Morphia is a MongoDB object-document mapper, developed in Java. It is based on the MongoDB-Java Driver and has the big advantage, that it is officially supported by MongoDB, because MongoDB developers support the Morphia codebase.

Comment: Eclipselink and HibernateOGM provide some JPA-implementation for MongoDB. But in my opinion, these implementations are a bit away from real productive usage. It lacks mainly the multiple hierarchical structure, which MongoDB supports with the document-centric approach.

Ok, now I want to show you, how you can map your first entity with Morphia:

@org.mongodb.morphia.annotations.Entity(value = "users", noClassnameStored = true)
public class User {

    @org.mongodb.morphia.annotations.Id
    private org.bson.types.ObjectId id;
    private String firstname;
    private String lastname;
    private Date birthdate;
    private String email;

    public User() {
    }


    public String getFullName() {
        return this.lastname + ", " + this.firstname;
    }

    // getter/setter/equals()/hashCode()
}

You declare a persistent entity for Morphia with the @Entity-annotation, exactly the same like in JPA. The parameter 'value' points to the collection in MongoDB, where these entities should be stored. By default, Morphia stores the fully qualified classname in the 'classname'-field. This field is automatically added by Morphia and is used for mapping the MongoDB-document back to the Java-entity. This sounds reasonable, but the main drawback of this is, that refactorings in your code are not synchronized with the MongoDB-documents. So, if you move one entity to another package, Morphia is no longer able to map this entity correctly, because the stored classname does not longer match with your code.
Or, we always have to do some 'migration' and update the classname-field to the new one in every document of the collection in question. If this collection is very big, such updates are not possible in a production environment. So, we provide the annotation-parameter 'noClassnameStored' with a value of 'true', so that the classname is not stored along with the document. Morphia has to do some more work to find out the right class for the correct mapping, but now we are more flexible and need not take care, that the classname of the entities is always in sync with the implementation.

Like each entity in JPA, every entity for Morphia and MongoDB needs a unique ID. MongoDB provides a very good concept of calculating a unique ID, namely an ObjectId (for more information on this topic, refer to
https://docs.mongodb.com/manual/reference/method/ObjectId/).
Morphia adopts this concept seamlessly. The only thing we have to do is to provide a property of type org.bson.types.ObjectId and annotate it with @org.mongodb.morphia.annotations.Id. Morphia will set this property transparently in background, when a new entity is persisted to MongoDB (we will see this later on) and fills it again transparently, when the entity is read back from MongoDB.

In order to persist this entity to MongoDB via Morphia-mapping, we must initialize Morphia. So, we extend our DBConnection class as follows:

public class DBConnection {
    private static MongoClient mongo;

    private static MongoClient mongo;
    private static Datastore datastore;


    public DBConnection() {
    }


    public void init() {
         if ((mongo == null) && (datastore == null)) {
             mongo = new MongoClient("localhost", 27017);
             Morphia morphia = new Morphia();
             datastore = morphia.createDatastore(mongo, "jmm");
         }
     }

     public Datastore getDatastore() {
         return datastore;
     }

}

From now on, the org.mongodb.morphia.Datastore has the functionality of an EntityManager. We can use it, for example, in the following way (the easiest way again is to show it in a test case):

@Test
public void persistEntityWithMorphia() {
    DBConnection dbConnection = new DBConnection();
    User testUser = new User();
    try {
        dbConnection.init();
        testUser.setFirstname("Max");
        testUser.setLastname("Mustermann");
        testUser.setBirthdate(new GregorianCalendar(1974, 10, 12, 0, 0).getTime());
        testUser.setEmail("max.mustermann@example.com");
        dbConnection.getDatastore().save(testUser);
        assertThat(testUser.getId(), notNullValue());
        final User retrievedUser =
                 dbConnection.getDatastore().find(User.class)
                         .filter("firstname", "Max").get();
        assertThat(retrievedUser.getLastname(), is("Mustermann"));
        assertThat(testUser.getId(), is(retrievedUser.getId()));
    } finally {
        dbConnection.getDatastore().delete(testUser);
    }
}

Our DBConncetion is instantiated as before. Morphia is initialized as well, completely transparently. The Datastore is available for further use via the DBConnection.getDatastore() method. Then we create our business object and set some properties.
In the next step we pass this business entity to the Datastore.save() method, which takes care of it and persists our entity to the "users" collection in MongoDB.
I want to point to the assert-statement for 'not null' for the Id-property of the user after the save method. Here we see, that Morphia automatically stores the ObjectId, which was generated by MongoDB while saving the entity to the MongoDB-collection, to the Id-property of our entity.
In the next step, we query our just persisted entity again from MongoDB. Here, we use the Datastore.find() method, where we provide the class as search-parameter and tell Morphia with this class, that we search for objects of the typ of this class. With this information at hand, Morphia knows, in which collection to search (it get's this information from the 'value'-parameter of the @Entity-annotation).
In addition, we provide a filter. In our case, we want to find all users, which have a firstname of 'Max'. In this test, we know, that we will only get exactly one result, so that we can use the Query.get() method, which gives us exactly one User entity as the result.

Comment: If we replace Query.get() with Query.iterator(), we get an iterator, exactly an Iterator<User>, and with this iterator, we can loop over the resulting collection of users.

Finally in our test case, we check, if we really have gotten the correct object from our query by comparing the unique ID properties.

In a real business application, every entity has several properties, which are only technical. This could be a timestamp, when this entity was initially created or when this entity was last changed. And the property for the last change must be updated with every call to Datastore.save(). But we do not want to take care of these technical properties in our business methods.
Additionally, I bet, that you (and me of course, too) will forget to update such technical properties at some time. So, we want to handle these aspects somewhere in the background automatically as a "cross-cutting-concern". For that, we define an abstract super-class, which all persistent entities have to extend:

public abstract class PersistentEntity {

    @org.mongodb.morphia.annotations.Id
    private ObjectId id;

    @org.mongodb.morphia.annotations.Version
    private Long version;

    @org.mongodb.morphia.annotations.Property
    private Date created;

    @org.mongodb.morphia.annotations.Property
    private Date lastUpdate;

    @PrePersist
    protected void prePersist() {
        if (created == null) {
            created = new Date();
        }
        this.lastUpdate = new Date();
    }

    public ObjectId getId() {
        return id;
    }

    // getter/setter/equals()/hashCode()
}

It is very important here to annotate our properties, which we want to have mapped in our entities, with @org.mongodb.morphia.annotations.Property. In a class, which is annotated with @Entity, all properties are mapped automatically by default. But in our abstract superclass, which is not annotated with @Entity, we must tell Morphia, which properties we want to have mapped from such an abstract superclass.
The attentive reader would have noticed, that I have added a field "version" which is annotated with @Version. This annotation works nearly the same as in JPA and takes care for an optimistic locking. When persisting the entity, Morphia looks first at the version field in the database, if it has the same value as in the object, which should currently be persisted. If it matches, everything is clear and the object is persisted. But if the value differs, Morphia knows, that some changes in between has occurred and rejects the persisting of this object. This field is automatically managed for you, you do not need to set a value here.

For the property "id", I only provide a getter-method. This should prevent our entity, that the "id" property is set or overridden by accident through application code.

In the User-object, we can delete the @Id-property, because now we inherit from PersistentEntity. And after that we have the big advantage, that we only declare business properties in our business entities. All the technical aspects are in the background.

@org.mongodb.morphia.annotations.Entity(value = "users", noClassnameStored = true)
public class User extends PersistentEntity {

    private String firstname;
    private String lastname;
    private Date birthdate;
    private String email;

    ...
}

If we now persist the entity with a call to Datastore.save(), the method with the annotaion @PrePersist is called first. In this method, we check, if we have a new entity or an existing/updated entity (in a new entity, the 'created' property is null), and only in the case of a new entity, we set the 'created' property with the current timestamp.
The property 'lastUpdate' should be set or updated with the current timestamp in any situation.

There are currently 5 lifecycle-methods, which are described here: https://github.com/mongodb/morphia/wiki/LifecycleMethods

We extend our last test-case with...

...
dbConnection.getDatastore().save(testUser);
assertThat(testUser.getId(), notNullValue());
assertThat(testUser.getCreated(), notNullValue());
assertThat(testUser.getLastUpdate(), notNullValue());
...

...and see, that it is green ;-). The two timestamps "created" and "lastUpdate" are set without setting them explicitly in our test case code.

JavaEE

First Strike

I hear you shout out loud: Where on earth is the JavaEE-part coming? Ok, let's integrated that with JavaEE. I assume, you have a JavaEE7-compatible server configured, so that we can deploy our application to it.

First of all I want to show you the BCE-package structure. BCE stands for Boundary, Control, Entity. There is a nice short introduction video to this topic of Java Champion Adam Bien at
https://www.youtube.com/watch?v=grJC6RFiB58.

This package-structure is perfect for Domain-Driven-Development, where every package-'container' (which consists of boundary, control and entity sub-package) is a part of the business domain. The 'boundary' and 'control' are both optional. In the boundary package, we put everything, which should be available to the outside-world for this business domain. For example, if we want to expose our list of users to an external system, we would provide a REST-service (eg. UsersResource), and this will go to the boundary package.

Everything, which is used inside of our application, for example, the list of users, which should be displayed on a web-page of our application, is implemented in a controller, which goes to the controller-package.

In our application, which we want to implement, there are 'users'. So we need an entity, namely the User-class, and some functionality around the user (adding, deletion and so on). So we structure our user-package like this:

 de/sofiworx/examples/jmm/business/user/boundary
 de/sofiworx/examples/jmm/business/user/controller
   UserController.class
 de/sofiworx/examples/jmm/business/user/entity
   User.class

The User class goes to the entity-package, our UserController goes to the controller-package. Boundary can be avoided, I list it here only for clarification.

Ok, let's make our DBConnection-class a Singleton EJB. For that, we annotate the DBConnection class:

@javax.ejb.Singleton
@javax.ejb.Startup
public class DBConnection {
...
}

These two annotation make the EJB a singleton (@Singleton) and instantiate this class first when starting the application (@Startup).

In addition, we annotate our DBConnection.init()-method with @PostConstruct, so that the database connection is initialized automatically when the DBConnection class is instantiated:

@javax.annotation.PostConstruct
public void init() {
    ....
}

Next, we annotate the DBConnection.getDatastore()-method with @Produces, so that we can inject the datastore in every managed bean (CDI, EJB).

Attention: It is important here to use "RequestScoped", because the Morphia-Datastore is currently not Serializable and an injection into Session or ViewScoped-beans leads to a Weld-Error while starting the application, because of injecting a non-serializable bean into a serializable bean.

 @javax.enterprise.inject.Produces
 @javax.enterprise.context.RequestScoped
 public Datastore getDatastore() {
     return datastore;
 }

A simple example for using the injected datastore is the UserController:

@javax.enterprise.context.SessionScoped
@javax.inject.Named
public class UserController implements Serializable {

    private static final long serialVersionUID = -6281169311696802773L;

    @Inject
    Datastore datastore;

    public long getCurrentAmountOfUsers() {
        return datastore.find(User.class).getCollection().getCount();
    }
}

We further need the typical JavaEE-WebApp Artifacts like beans.xml, web.xml and faces-config.xml (because our frontend will be based on JSF), which we will put into the ``src/main/webapp/WEB-INF` folder.

beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                           http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
       bean-discovery-mode="all">
</beans>

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                             http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

    <context-param>
        <param-name>javax.faces.PROJECT_STAGE</param-name>
        <param-value>Development</param-value>
    </context-param>
    <context-param>
        <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
        <param-value>true</param-value>
    </context-param>


    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.xhtml</url-pattern>
    </servlet-mapping>

    <session-config>
        <session-timeout>30</session-timeout>
        <tracking-mode>COOKIE</tracking-mode>
    </session-config>

    <welcome-file-list>
        <welcome-file>index.xhtml</welcome-file>
    </welcome-file-list>

</web-app>

faces-config.xml:

<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="2.2"
              xmlns="http://xmlns.jcp.org/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                                  http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd">
    <application>
    </application>
</faces-config>

Finally, we need the index.xhtml page, so that we can display our first message from our application:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core">

    <f:view>
        <h:body>
            <h:outputText value="Hello from JavaEE with MongoDB. Currently, there are #{userController.getCurrentAmountOfUsers()} users in the database."/>
        </h:body>
    </f:view>
</html>

We see, that we use the UserController-class from above, where the datastore is injected, so that we have direct access to our database-layer.

If we deploy the application to our JavaEE7-server, start it and call the index-page in the browser, we should see something like this: "Hello from JavaEE with MongoDB. Currently, there are 0 users in the database."

You see the simplicity in initialization of the persistence-layer. It is one class (DBConnection), and we only need to inject the Datastore, where ever we need the persistence-layer. And because of the document-centric approach, we need not care about transactions in the first place. The complete document is stored at once. This is very helpful in case of complex data structures, which we will see later on.

If there is a conflict with concurrent access to the same entity, this is handled or better signalled by the @Version annotated field of our entities. If this situation occurs, a java.util.ConcurrentModificationException is thrown, which we need to handle according to the concrete business situation. It is not possible to handle this generically, because it depends really on the business use case.

There are situations, where a so called "Two-face-commit" is needed, and there is a detailed article from MongoDB about this topic and how to implement this. Here is the link to the article:
https://docs.mongodb.com/v3.0/tutorial/perform-two-phase-commits/

And, of course, even if we use a JavaEE-environment, our persistence-tests can be performed without the use of a testing framework like Arquillian. We can just use plain JUnit-tests for that. We don't need complicated persistence.xml for tests with a different database configuration, perhaps a different dialect-setup or something like that. We only need a test MongoDB instance, ideally locally started to run our persistence-tests against.

Comment: I will cover testing with MongoDB in a future article.

OK, now we want to extend our application to setup a page for user-management, where we see a list of our users, and where we can add and remove users to our system. For that, we extend our User-class:

@org.mongodb.morphia.annotations.Entity(value = "users", noClassnameStored = true)
public class User {

    private String firstname;
    private String lastname;
    private Date birthdate;
    private String email;

    @org.mongodb.morphia.annotations.Embedded
    private Address address;

    ...
}
@org.mongodb.morphia.annotations.Embedded
public class Address {

    private String street;
    private String streetNo;
    private String zipCode;
    private String city;

    public Address() {
    }

    // getter/setter/equals()/hashCode()
}

Here, we define a so-called embeddable, which can be seen as sub-document. The MongoDB-document will later look like this, for example:

{
    "_id" : ObjectId("12345678909876543456"),
    "firstname" : "Bruce",
    "lastname" : "Wayne",
    "birthdate" : null,
    "email" : "batman@gotham.org",
    "address" : {
        "street" : "Main Street",
        "streetNr" : "1",
        "zipCode" : "12345",
        "city" : "Gotham"
    }
}

Now, we extend the UserController for our JSF-page:

@javax.enterprise.context.SessionScoped
@Named
public class UserController implements Serializable {

    private static final long serialVersionUID = -6281169311696802773L;

    private User userToAdd;

    private List<User> usersToShow;

    private String searchString;

    @Inject
    @RequestScoped
    private Datastore datastore;


    public UserController() {
    }

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

    public long getCurrentAmountOfUsers() {
        return datastore.find(User.class).getCollection().getCount();
    }

    private void showAllUsers() {
        usersToShow = datastore.createQuery(User.class).order("lastname,firstname").asList();
    }

    public void prepareNewUser() {
        userToAdd = new User();
    }

    public String addNewUser() {
        datastore.save(userToAdd);
        userToAdd = null;
        showAllUsers();
        return null;
    }

    public void removeUser(User userToDelete) {
        datastore.delete(userToDelete);
        showAllUsers();
    }

    public void searchUsers(String stringToSearch) {
        final Query<User> query = datastore.createQuery(User.class);
        if (stringToSearch != null) {
            query.or(query.criteria("firstname").contains(stringToSearch),
                     query.criteria("lastname").contains(stringToSearch));
        }
        usersToShow = query.asList();
    }

    @Produces
    @Named
    public User getUserToAdd() {
        return userToAdd;
    }

    public List<User> getUsersToShow() {
        return usersToShow;
    }

    public String getSearchString() {
        return searchString;
    }

    public void setSearchString(String searchString) {
        this.searchString = searchString;
    }
}

Then, we extend the index.xhtml:

    <f:view>
        <h:body>
            <div>
                <h:outputText value="Hello from JavaEE with MongoDB. Currently, there are #{userController.getCurrentAmountOfUsers()} user in the database."/>
            </div>
            <div>
                <h:link value="User-Management" outcome="users" />
            </div>
        </h:body>
    </f:view>

And finally the users.xhtml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core">

    <f:view>
        <h1><h:outputLabel value="Users"/></h1>

        <h:panelGrid columns="2">
            <h:form>
                <h:inputText value="#{userController.searchString}" />
                <h:commandButton value="Search"
                                 actionListener="#{userController.searchUsers(userController.searchString)}">
                    <f:ajax execute="@form" render="userListForm" />
                </h:commandButton>
            </h:form>
        </h:panelGrid>

        <h:form id="userListForm">
            <h:dataTable id="usersTable" value="#{userController.usersToShow}"
                         var="user" style="border: 1px solid;">
                <h:column>
                    <f:facet name="header">
                        Lastname
                    </f:facet>
                    <h:outputText value="#{user.lastname}" />
                </h:column>
                <h:column>
                    <f:facet name="header">
                        Firstname
                    </f:facet>
                    <h:outputText value="#{user.firstname}" />
                </h:column>
                <h:column>
                    <f:facet name="header">
                        eMail
                    </f:facet>
                    <h:outputText value="#{user.email}" />
                </h:column>
                <h:column>
                    <f:facet name="header">
                        Birthdate
                    </f:facet>
                    <h:outputText value="#{user.birthdate}">
                        <f:convertDateTime dateStyle="short" locale="en-US" />
                    </h:outputText>
                </h:column>
                <h:column>
                    <h:commandButton value="Delete"
                                     actionListener="#{userController.removeUser(user)}" >
                        <f:ajax execute="@this" render="usersTable" />
                    </h:commandButton>
                </h:column>
            </h:dataTable>
        </h:form>

        <h:panelGrid>
            <h:form>
                <h:commandButton value="New User"
                                 actionListener="#{userController.prepareNewUser()}">
                    <f:ajax execute="@this" render="newUserGrid" />
                </h:commandButton>
            </h:form>
        </h:panelGrid>
        <h:panelGroup id="newUserGrid" rendered="#{not (userToAdd eq null)}">
            <h:form id="newUserForm">
                <h:panelGrid columns="2">
                    <h:outputLabel value="Firstname" />
                    <h:inputText value="#{userToAdd.firstname}" />
                    <h:outputLabel value="Lastname" />
                    <h:inputText value="#{userToAdd.lastname}" />
                    <h:outputLabel value="eMail" />
                    <h:inputText value="#{userToAdd.email}" />
                    <h:outputLabel value="Birthdate" />
                    <h:inputText value="#{userToAdd.birthdate}">
                        <f:convertDateTime type="date" pattern="MM.dd.yyyy" locale="en-US"/>
                    </h:inputText>
                    <h:outputLabel value="Street" />
                    <h:inputText value="#{userToAdd.address.street}" />
                    <h:outputLabel value="Street No." />
                    <h:inputText value="#{userToAdd.address.streetNo}" />
                    <h:outputLabel value="Zipcode" />
                    <h:inputText value="#{userToAdd.address.zipCode}" />
                    <h:outputLabel value="City" />
                    <h:inputText value="#{userToAdd.address.city}" />
                    <h:outputLabel value="" />
                    <h:commandButton value="Add" action="#{userController.addNewUser}" />
                </h:panelGrid>
            </h:form>
        </h:panelGroup>
    </f:view>

</html>

Now we have a first running example with quite some functionality like searching (with using the Morphia-query), adding new users and deleting existing users. Not really much code, isn't it?

Extending the application with references and custom type-converter

In the next section, we will cover quite a lot of things at once.
First, we see, how to map references to other entities, as well as the mapping of a list of embedded objects. Second, we will look at, how we can enhance Morphia with a custom type-converter. This is useful, if we have some entity-types, which are not the basic ones like String or Numbers. For example, the BigDecimal, which is quite important to store prices, cannot be instantiated by Morphia because of the missing default constructor in BigDecimal. So we need a custom Morphia-converter to map BigDecimals back and forth.

Ok, our application needs some articles or products which we can order. So, let's start with defining the product: we save the Product-class in .../jmm/business/product/entity/Product.java

@Entity(value = "products", noClassnameStored = true)
public class Product extends PersistentEntity {

    private static final long serialVersionUID = -7245514305118509921L;

    private String productNo;

    private String description;

    private BigDecimal price;

    @org.mongodb.morphia.annotations.Transient
    private boolean selected;


    public Product() {
    }


    public String getSummary() {
        return this.productNo + ", " + this.getDescription() + ", " + this.getPrice().toString();
    }

    // getter/setter/equals()/hashCode()

Everything cristal clear and not really new stuff, isn't it? There is only this @Transient-annotation. It is the same behaviour like in JPA, that this property is not mapped and persisted into the database. And if the entity is read from database, a transient property contains always the default value for the corresponding data type.

For simplicity, we initialize the products programmatically, if they do not already exists. Therefore, we write a simple factory, which creates some products on startup .../jmm/business/product/controller/ProductStartupFactory.java:

@Startup
@DependsOn("DBConnection")
@Singleton
public class ProductStartupFactory {

    @Inject
    Datastore datastore;

    @PostConstruct
    private void init() {
        if (datastore.find(Product.class).countAll() == 0) {
            for (int i = 1; i < 12; i++) {
                Product product = new Product();
                product.setProductNo(Integer.toString(i));
                product.setDescription("Description of article with no. " + i);
                product.setPrice(new BigDecimal(i));
                datastore.save(product);
            }
        }
    }
}

Now, at every startup, the application looks, if there are products in the database and if not, some products are created, otherwise nothing is done.

Before we can buy some products, we need to 'define' the current user. In a real application, this is done via login and then there is one current user in the session. In our case, we will simplify things a bit and select the current user from our users list via a button. Therefore, in users.xhtml, we extend our h1-tag with

<h1>
    <h:outputText value="Users"/>
    <h:panelGroup id="userLabel" style="display: inline" rendered="#{not (currentSelectedUser eq null)}">
        <h:outputText value=" (#{currentSelectedUser.getFullName()})" />
    </h:panelGroup>
</h1>

In addition, we put a new column to our users-table so select one user as the current user of our order-session:

<h:column>
    <f:facet name="header">
        Select for orders
    </f:facet>
    <h:commandButton value="select"
                     actionListener="#{userController.setCurrentSelectedUser(user)}">
        <f:ajax execute="@this" render="userLabel" />
    </h:commandButton>
</h:column>

And finally, at the bottom of the users-page, we need a link to our order-page (which we will implement in a moment):

    ...
        <h:panelGroup layout="block" style="margin-top: 20px;"
                      rendered="#{not (currentSelectedUser eq null)}" >
            <h:link outcome="orders" value="Goto orders" />
        </h:panelGroup>
    </f:view>
</html>

Ok, that's all for the users-page. To make this 'compilable', we had to extend the UserController. First, we need a property for the current selected user and the corresponding get/set-methods:

    private User currentSelectedUser;

    ...

    public void setCurrentSelectedUser(User currentSelectedUser) {
        this.currentSelectedUser = currentSelectedUser;
    }

    @Produces @de.sofiworx.examples.jmm.platform.cdi.Current
    @Named
    @javax.enterprise.context.Dependent
    public User getCurrentSelectedUser() {
        return currentSelectedUser;
    }

The interesting part here are the annotations at the getCurrentSelectedUser() method. In order to inject and use the current selected user, we annotate it with @Produces and @Named, so we can use it in our JSF-page as well. But we have already a method, which produces a User-object (via the getUserToAdd()-method), so we have to add a qualifier annotation to distinguish between the both methods. The qualifier annotation is simply defined:

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
public @interface Current {}

Now we can set the current user of our session via the button in the users-table. After selecting an user, the full name of this selected user is displayed at the top of the users-page and the link to the orders-page is displayed.

Next, we need a controller for the products .../jmm/business/product/controller/ProductController.java:

@ViewScoped
public class ProductController implements Serializable {

    private static final long serialVersionUID = -4166516355114826188L;

    @Inject
    Datastore datastore;

    @Produces
    @Named
    private List<Product> allAvailableProducts;


    public ProductController() {
    }


    @PostConstruct
    private void init() {
        allAvailableProducts = datastore.find(Product.class).asList();
    }

    public List<Product> getAllAvailableProducts() {
        return allAvailableProducts;
    }
}

Finally, we will have a problem, when we persist a property with type BigDecimal. For example, if we store a BigDecimal with value "4.01", this property is persisted in MongoDB as:

"bigDecimalValue": {
    "scale": 2,
    "precision": 3,
    "intCompact": NumberLong(401)
  },

But if we read such an entity withthis BigDecimal property via Morphia from MongoDB, we will get a RuntimeException:

java.lang.RuntimeException: org.mongodb.morphia.mapping.MappingException:
   No usable constructor for java.math.BigDecimal

Morphia cannot instantiate a BigDecimal and set the stored values back, because BigDecimal has no default constructor. But Morphia provides an easy way to overcome this situation with custom converters. There are only two methods, which you have to override, and we decide to use the String-representation of the BigDecimal for storing its value in Mongo. Such a custom converter can look like this:

public class BigDecimalConverter extends org.mongodb.morphia.converters.TypeConverter
                                 implements org.mongodb.morphia.converters.SimpleValueConverter {

    public BigDecimalConverter() {
        super(BigDecimal.class);
    }

    @Override
    public Object encode(final Object value, final MappedField optionalExtraInfo) {
        if (value == null) {
            return null;
        }
        return value.toString();
    }

    @Override
    public Object decode(final Class targetClass, final Object fromDBObject,
                         final MappedField optionalExtraInfo) throws MappingException {
        if (fromDBObject == null) {
            return null;
        }
        return new BigDecimal(fromDBObject.toString());
    }
}

Of course, the custom converters must be registered for Morphia. We do this in our DBConnection.init()-method:

morphia.getMapper().getConverters().addConverter(BigDecimalConverter.class);

Order-page

In order to make our link to the order page work, we have to implement the orders.xhtml-page. On this page, we want to display the recent orders of the current user. Furthermore, we display all available products in a table, which can be selected via checkbox. And of course, we need a button to submit the order, so the user can order his selected products. After an order is submitted, the order is displayed in the top table for the current user.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core"
      xmlns:ui="http://xmlns.jcp.org/jsf/facelets">

    <f:view>
        <h1>
            <h:outputText value="Orders"/>
            <h:panelGroup id="userLabel" style="display: inline"
                          rendered="#{not (currentSelectedUser eq null)}">
                <h:outputText value=" (#{currentSelectedUser.getFullName()})" />
            </h:panelGroup>
        </h1>

        <h:panelGroup layout="block" style="margin-top: 20px;">
            <h:dataTable value="#{allOrdersOfCurrentUser}" var="order"
                         style="border: 1px solid;">
                <h:column>
                    <f:facet name="header">
                        Order date
                    </f:facet>
                    <h:outputText value="#{order.orderDate}" />
                </h:column>
                <h:column>
                    <f:facet name="header">
                        Total amount
                    </f:facet>
                    <h:outputText value="#{order.totalAmount}" />
                </h:column>
                <h:column>
                    <f:facet name="header">
                        Ordered products
                    </f:facet>
                    <h:panelGroup>
                        <ul>
                            <ui:repeat value="#{order.orderedProducts}" var="product">
                            <li>
                                <h:outputText value="#{product.getSummary()}" />
                            </li>
                            </ui:repeat>
                        </ul>
                    </h:panelGroup>
                </h:column>
            </h:dataTable>
        </h:panelGroup>

        <h:panelGroup layout="block" style="margin-top: 20px;">
            <h:form>
                <h:dataTable value="#{allAvailableProducts}" var="product"
                             style="border: 1px solid;">
                    <h:column>
                        <f:facet name="header">
                            Product No.
                        </f:facet>
                        <h:outputText value="#{product.productNo}" />
                    </h:column>
                    <h:column>
                        <f:facet name="header">
                            Description
                        </f:facet>
                        <h:outputText value="#{product.description}" />
                    </h:column>
                    <h:column>
                        <f:facet name="header">
                            Price
                        </f:facet>
                        <h:outputText value="#{product.price}" >
                            <f:convertNumber maxFractionDigits="2" minFractionDigits="2"
                                             locale="en-US" />
                        </h:outputText>
                    </h:column>
                    <h:column>
                        <h:selectBooleanCheckbox value="#{product.selected}" />
                    </h:column>
                </h:dataTable>
                <h:commandButton value="Submit order"
                                 action="#{orderController.placeOrder}">
                    <f:ajax render="@all" execute="@form" />
                </h:commandButton>
            </h:form>
        </h:panelGroup>

        <h:panelGroup layout="block" style="margin-top: 20px;">
            <h:link value="Back to users" outcome="users" />
        </h:panelGroup>
    </f:view>
</html>

Ok, the page was easy, now we need to implement the business logic. First, we start with the Order-class, which we store in:
de/sofiworx/examples/jmm/business/order/entity/Order.java

@Entity(value = "orders", noClassnameStored = true)
public class Order extends PersistentEntity {

    private static final long serialVersionUID = 7958903679851324189L;

    private Date orderDate;

    private BigDecimal totalAmount;

    @org.mongodb.morphia.annotations.Reference
    private User user;

    @org.mongodb.morphia.annotations.Embedded
    private List<Product> orderedProducts;

    // getter/setter/equals()/hashCode()
}

Our Order-object would be very simple and only contains the date of the order, the total amount of all ordered products, the reference to the user, who placed the order and of course the list of the products. It is important here, that we don't store only references to the products but the products as a whole. This is important for the business case, that we need the prices and the state of the products to the time, when they are ordered. If someone changes the price in the central product-collection, this changes does not affect already placed orders.

Next, we need the OrderController, which we store in
de/sofiworx/examples/jmm/business/order/controller/OrderController.java:

@ViewScoped
@Named
public class OrderController implements Serializable {

    private static final long serialVersionUID = 3341943397531831252L;

    @Inject
    Datastore datastore;

    @Inject @Current
    User currentSelectedUser;

    @Inject
    ProductController productController;

    private List<Order> allOrdersOfCurrentUser;


    public OrderController() {
    }


    @PostConstruct
    private void init() {
        final Query<Order> query = datastore.createQuery(Order.class);
        query.criteria("user").equal(currentSelectedUser);
        allOrdersOfCurrentUser = query.asList();
        productController.getAllAvailableProducts().stream()
                .forEach(p -> p.setSelected(false));
    }


    @Produces
    @Named
    public List<Order> getAllOrdersOfCurrentUser() {
        return allOrdersOfCurrentUser;
    }

    public void placeOrder() {
        final List<Product> selectedProducts =
                productController.getAllAvailableProducts().stream()
                        .filter(Product::isSelected)
                        .collect(Collectors.toList());
        Order order = new Order();
        order.setOrderDate(new Date());
        order.setUser(currentSelectedUser);
        order.setOrderedProducts(selectedProducts);
        Function<Product, BigDecimal> totalMapper = Product::getPrice;
        BigDecimal total = selectedProducts.stream()
                .map(totalMapper).reduce(BigDecimal.ZERO, BigDecimal::add);
        order.setTotalAmount(total);
        datastore.save(order);
        init();
    }

}

And last but not least, we need the ProductController, which provides access to our products-list. We store it in
de/sofiworx/examples/jmm/business/product/controller/ProductController.java:

@ViewScoped
public class ProductController implements Serializable {

    private static final long serialVersionUID = -4166516355114826188L;

    @Inject
    Datastore datastore;

    @Produces
    @Named
    private List<Product> allAvailableProducts;


    public ProductController() {
    }


    @PostConstruct
    private void init() {
        allAvailableProducts = datastore.find(Product.class).asList();
    }

    public List<Product> getAllAvailableProducts() {
        return allAvailableProducts;
    }
}

And that's it. You see, MongoDB, JavaEE and Morphia fit together perfectly. With minimal code, we have implemented quite some functionality in our Web-application. And we have only touched the surface. MongoDBs big advantage, that it is schema-less, comes into play, if you change/extend your business objects. You don't have to update the database, just add the property to your business object and nothing more.

I hope, you find this article somewhat helpful and I appreciate every kind of feedback on this. You can reach me on developer(at)cech-home.de