<body><script type="text/javascript"> function setAttributeOnload(object, attribute, val) { if(window.addEventListener) { window.addEventListener('load', function(){ object[attribute] = val; }, false); } else { window.attachEvent('onload', function(){ object[attribute] = val; }); } } </script> <div id="navbar-iframe-container"></div> <script type="text/javascript" src="https://apis.google.com/js/platform.js"></script> <script type="text/javascript"> gapi.load("gapi.iframes:gapi.iframes.style.bubble", function() { if (gapi.iframes && gapi.iframes.getContext) { gapi.iframes.getContext().openChild({ url: 'https://www.blogger.com/navbar.g?targetBlogID\x3d8334277\x26blogName\x3dSriram\x27s+Blog\x26publishMode\x3dPUBLISH_MODE_BLOGSPOT\x26navbarType\x3dBLUE\x26layoutType\x3dCLASSIC\x26searchRoot\x3dhttps://metallicatony.blogspot.com/search\x26blogLocale\x3den\x26v\x3d2\x26homepageUrl\x3dhttp://metallicatony.blogspot.com/\x26vt\x3d6147907796332168684', where: document.getElementById("navbar-iframe-container"), id: "navbar-iframe" }); } }); </script>

Wednesday, December 31, 2014

CRUD REST APIs using Java, MongoDB, Spring, Spring Data, Apache CXF, Maven and SLF4J

This project shows how to build a web application and perform basic CRUD operations using MongoDB as the datastore. It exposes the built operations as REST web services or APIs too. I created this primarily to show how to incorporate and kickstart MongoDB in web applications. And hence this post focuses more on MongoDB than anything else. I would recommend referring my previous posts if you would like to know the basics of building a web app CRUD REST & SOAP Services using Java and Apache CXF.

The following were used to build this project
1) Java 1.6
2) Spring Tool suite (STS) 3.1.0
3) Spring framework 4.0.0
4) Spring Data 1.6.1
5) Apache CXF 2.7.5
6) Apache maven 3.0.4
7) Log4j 1.2.16 and Slf4j 1.6.1
8) Jackson 1.9.0
9) SOAP UI 4.5.1
10) MongoDB 2.6.4

Objective
The objective of this project is to demonstrate a simple CRUD operation on a set of employee information in MongoDB. All the CRUD operations are exposed as REST webservices and so they can be invoked through any type of web client like SOAPUI or even using a simple web browser.

About MongoDB
Mongo DB is one of the most popular NoSQL database that persists information as JSON-style documents without enforcing a schema or a defined structure. This type of storage and retrieval is very helpful in types of applications where speed, performance and scaling overweigh data redundancy. The best documentation I have found so far is Mongo’s own official manual MongoDB Official Manual.

Install & configure MongoDB
Before proceeding to build the web app, it is required to install and configure MongoDB by following MongoDB Official Installation Instructions . A basic level of understanding about mongo concepts and commands are needed (MongoDB official CRUD operations) before proceeding further.
The next few steps are needed to prep MongoDB before proceeding to build the webapp. After installing MongoDB, let’s make MongoDB to NOT allow anonymous logins. And that's how a typical installation will be in an enterprise. This needs Mongo daemon/server to be started in “auth” mode. But before starting in "auth" mode, we need to create an administrator user.

1) Create administrator user via mongo console
> db.createUser({user: "administrator", pwd: "password", roles: [ {role: "userAdminAnyDatabase", db: "admin"}]});
Successfully added user: {
        "user" : "administrator",
        "roles" : [
                {
                        "role" : "userAdminAnyDatabase",
                        "db" : "admin"
                }
        ]
}

2) Create one more non-admin/regular user who has RW permission for all databases in MongoDB
> db.createUser({user: "metallicatony", pwd: "password", roles: [{role: "readWriteAnyDatabase", db:"admin"}]});
Successfully added user: {
        "user" : "metallicatony",
        "roles" : [
                {
                        "role" : "readWriteAnyDatabase",
                        "db" : "admin"
                }
        ]
}

3) Start Mongo daemon in “auth” mode
 C:\Program Files\MongoDB 2.6 Standard\bin> mongod.exe --auth --dbpath "C:\Program Files\MongoDB 2.6 Standard\data\db" 

4) Test whether Mongo allows anonymous operations. It won’t.
> show dbs
2014-12-30T10:08:17.669-0800 listDatabases failed:{
        "ok" : 0,
        "errmsg" : "not authorized on admin to execute command { listDatabases: 1.0 }",
        "code" : 13
} at src/mongo/shell/mongo.js:47

5) Authenticate with the non-admin user created in step 2)
> db.auth("metallicatony", "password");
1

6) Database “organization” and collection “employees” are something that will be used in our webapp. Switch to database “organization” and insert a new document in a collection called “employees”.
> use organization;
switched to db organization


> db.employees.insert({empId: 1, fname: "Richard", lname: "Stallman", deptName: "CS", salary: 5000});
WriteResult({ "nInserted" : 1 })


> db.employees.find();
{ "_id" : ObjectId("54a32c39961019d59eacd4ce"), "empId" : 1, "fname" : "Richard", "lname" : "Stallman", 
 "deptName" : "CS", "salary" : 5000 }

> db.sequence.insert({empId: 1});
WriteResult({ "nInserted" : 1 })

With that done, the installation and prep work of mongodb is complete. The next steps focus on building the web application that will interact with MongoDB. This basic web application will have the CRUD capabilities - create, read, update and delete employees from mongodb.

POM Changes
Spring Data is the backbone for all the interactions that are performed between the web application and the MongoDB. Spring data provides a consistent programming model and lets java programmers to use all the features of MongoDB using a repository style data access layer. To include spring data for mongodb as part of the project, the following additions are made to the application’s pom.

Add the version of spring data mongodb in the pom properties
1.6.1.RELEASE
Add the dependency under pom dependencies

  org.springframework.data
  spring-data-mongodb
  ${spring.data.mongo.version}


MongoDB connection properties & Application context configuration
The connection properties of MongoDB are stored in a file called "database.properties" and resolved when spring loads "applicationContext.xml" file.
  mongo.hostname=localhost
  mongo.port=27017
  mongo.username=metallicatony
  mongo.password=password
  mongo.databaseName=organization
The below property placeholder configuration from applicationContext.xml file loads the properties

Added to that, below are the bean definitions in applicationContext.xml file to instantiate a "mongoTemplate" that will be injected into Spring repository. The web application interacts with the Mongo layer using the repository.


 
 

 


    
    




 
 
 

Web application descriptor's (web.xml) context config location parameter points to the xml files that contain bean definitions. In our application, it points to both cxf-bean.xml and applicationContext.xml files. Below is a snippet from web.xml

  contextConfigLocation
    
     classpath*:cxf-bean.xml,
     classpath*:applicationContext.xml
    


Application Code Layers
The web app code is organized into 7 layers wherein every layer corresponds to a package. The layers are
  • Service Layer - contains the interface and implementation of the APIs exposed 
  • Request Layer - contains the API request entities 
  • Response Layer - contains the API response entities 
  • Adapter Layer - contains helper methods that can convert entity of one type to other 
  • Business Layer - lies in between service and repository layer and applies any business logics if any 
  • Domain Layer - contains domain entities, more specifically for this project, it comprises entities that represent mongo documents 
  • Repository Layer - the layer down in the stack that bundles all the mongo queries to perform the desired operation in mongo database 

Repository & Domain Layers
The layers other than repository and domain layers are pretty much self-learnable from the code. Moreover the code follows a similar pattern like that was discussed in the previous posts about building CRUD REST and SOAP APIs and building CRUD operations using Spring and Hibernate. The domain layer contains two entities - Employee and Sequence. The employee entity is the one that maps to any document in "employees" collection that was created in step 6. This is done by using @Document annotation. This is more similar to mapping an entity to a table record in a database table.
@Document(collection="employees")
Sequence entity maps to a special counters collection called "sequence". Every employee id is an auto incremented sequence number that is generated during run time. More about this can be read from mongo's official manual Creating auto incrementing sequence number . In our case, the helper method "getNextId()" handles the job of fetching the sequence document and returning the incremented sequence number like this
 /**
  * Gets the next sequence id
  * @return the sequence id
  */
 public Long getNextId() {
  // Get object id of the sequence document
  Query queryGet = new Query(Criteria.where("empId").exists(true));
  Sequence sequenceDocGet = mongoTemplate.findOne(queryGet, Sequence.class);
  log.info("objectId={}", sequenceDocGet.get_id());
  
  // Increment emp id of the document fetched above and return the new sequence number
  Sequence sequenceDoc = null;
  Update update = new Update();
  update.inc("empId", 1);
  Query query = new Query(Criteria.where("_id").is(new ObjectId(sequenceDocGet.get_id())));
  FindAndModifyOptions options = new FindAndModifyOptions();
  options.returnNew(true);
  sequenceDoc = mongoTemplate.findAndModify(query, update, options, Sequence.class);
  if (sequenceDoc != null) {
   return sequenceDoc.getEmpId();
  }
  return null;
 }
The code for repository layer resides in EmployeeRepository class. All the mongo specific operations are possible from this layer by spring injecting mongo template
@Autowired
private MongoTemplate mongoTemplate;
The repository layer comprises operations to
  • find all employees (this operation is exposed as REST API - HTTP GET /employees)
  • find all employees by last name (this operation is exposed as REST API - HTTP GET /employees?lname="name")
  • find employee by employee id (this operation is exposed as REST API - HTTP GET /employees/{empId})
  • create employee (this operation is exposed as REST API - HTTP POST /employees)
  • update employee (this operation is exposed as REST API - HTTP PUT /employees/{empId})
  • delete employee (this operation is exposed as REST API - HTTP DELETE /employees/{empId})
Most part of the code involved in performing the above operations is about creating the right Mongo Query and running it using the injected mongo template. Being comfortable with basic mongo query syntax will help a lot here. Feel free to download, build and browse through the code from my GitHub repository - CRUD APIs using Mongo.

Labels: ,