Showing posts with label nosql. Show all posts

Spring and Neo4J integration - A Quick WebApp



Following my experimentation with MongoDB and the SpringData integration, I was keen to try out a few other NoSQL options - notably something outside of a document based data store. I had heard about a competition asking for submissions for Neo4J on the Heroku platform, which initially sparked my interest (although as of yet I have not tried it on Heroku) and seeing as Spring Data already had the Neo4J integration I thought I would have a go at it. Plus, I enjoy graphs as a data structure. I have fairly recently done some work on graphs having to implement Dijkstra's algorithm (also the A*) so this seemed like it was going to be fun.

Firstly, the documentation, in the form of an online e-book, for Neo4J Spring Data is awesome. Some guys have put together the e-book based on their experience setting up a Neo4J website and it really does cover everything from the first steps through to more complex stuff around traversal and transaction management. This also means, there is little point in me going through my every step in my app, as it wouldnt be very different from their advice, so most importantly, read this!!!

I will however, just highlight some interesting points i discovered along the way:

1. Simple Annotation based Entites
As you would expect, much like JPA or MongoDB, Neo4J supports simple annotation based configuration of your domain model to simply and quickly describe some pretty rich graph relationships. This is not that unexpected, as it is Spring after all, but worth noting that it is pretty comprehensive and easy to use.


2. Magic Repository Methods
A bit like in Grails, the Neo4J supports "magic" methods, that allow you to just define method names and the query implementation will be completed for you. For example, in your Movie repository (As per the book example, and also my example) if you defined a method such as:

Movie getMovieById(String id);

Then you do not need to provide an implementation, and Spring will automagically do the rest. (the convention being get[DOMAIN_ENTITY]By[ENTITY_PROPERTY]()

From the book: "In our wildest dreams we imagined the method names we would come up with, and what kinds of queries those could generate"

3. Arbor JS Graph Framework
A little while ago I discovered the Arbor JS framework for visualisation of graphs, and its really nice - I had to try and achieve something similar some time last year and got some of the way using core html5/JS but this library is a lot more comprehensive so wanted to have a go.
First, you should check out the demos over at http://arborjs.org/, they are really nice, and make for a really nice graph UI (see screenshot of my app).


4. The Data
I wanted to get some real data, and looked at a few big datasets available online such as the Stanford Large Data Set Network but being as Im only running locally, and I didnt really want to spend too much time getting the data into my graph model I decided to go for a far smaller, simpler dataset - this years Oscar nominations (actors/directors/movies/awards - hopefully you can make out the graph from the screenshot). The data I got from the Guardian (probably UK only) data set blog which also had some nice data sets in it, but this one seemed to be a small enough size for me not to loose too much time to the data.


As always, the code is up on my github, so feel free to check it out, fork/download/mistreat etc..

Integrating MongoDB & Spring

Further to my previous post with a deck walking through MongoDB & Spring integration, I also recently wrote it up as a technical article for work (my day job), and I thought I would share the detailed article here for you as well..


Introduction

With the explosion in the amounts of data being generated in recent years, more and more organisations are looking at alternative data storage options to the traditional relational model. This in turn has lead to huge growth in the NoSQL space, with leading web companies such as Facebook, Google, Twitter, Reddit, etc adopting NoSQL solutions.
Within the NoSQL space there are several different implementation options (Graph based DBs such as Neo4J, Wide Column DBS such as Cassandra and Haddop, Document based DBs such as MongoDB and CouchDB) and careful consideration is needed before choosing an implementation.
This article will look at integrating the Document oriented database MongoDB with a Spring MVC Web Application – it is important to note that due to the nature of Document based storage solutions, they are not applicable for all problems. For example, if the data you are modelling cannot naturally be stored as “documents”, then a Document-oriented DB probably isn’t the best solution (an easy way to think about whether the model can be stored as a document is to think of it being stored on paper – does it make sense for all the elements to be intrinsically grouped in to a single document? E.g. if you were storing an essay, all the chapters are intrinsically linked to the essay as a whole document, and a single chapter doesn’t make much sense as an individual object on its own).
For that reason, this article will look at a simple web app that allows users to create Resumes – Similar to an essay, resume storage is naturally suited to the Document based approach rather than a Relational approach.


Getting Started

This article will not cover details of creating a Spring MVC web application, and will assume a prior knowledge of the Spring MVC framework and core Spring principles. The example application itself is very simple, and there are several aspects of it that have not been included (these have been intentionally left out for simplicity), such as security/authentication features, advanced UI/screen flow/editing, etc, the purpose of the example application is purely to demonstrate MongoDB integration with Spring.
The source code for the application is all available from my GitHub Account (see links on the right), and if you want to follow the code below are the required pre-requisites:
  • Install MongoDB – this is a straight forward process and details can be found here: http://www.mongodb.org
  • Install Maven – the example project uses Maven to manage it dependencies, details can be found here: http://maven.apache.org/
  • Install STS Eclipse build and install the CloudFoundry extension (Optional) – If you want to follow the steps to deploy the application to the cloud then this is required
  • Sign up for a CloudFoundry account (www.cloudfoundry.com) (Optional) – Currently in Beta so its recommended that you sign up for the account as soon as possible as requests can take time to come through






Project Dependencies

Spring currently has a project underway to integrate core Spring functionality with various non–relational data technologies, including MongoDB, called “Spring Data”. We will use this library to facilitate our integration, so we will need to include the following maven dependency in our project pom:

              <dependency>
                     <groupId>org.springframework.data</groupId>
                     <artifactId>spring-data-mongodb</artifactId>
                     <version>1.0.0.M3</version>
              </dependency>


We also need to include the MongoDB Java driver:

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


And finally, to deploy on to CloudFoundry’s hosted service we need their runtime library:

              <dependency>
                     <groupId>org.cloudfoundry</groupId>
                     <artifactId>cloudfoundry-runtime</artifactId>
                     <version>0.7.1</version>
              </dependency>




Building the Domain Model

If you are familiar with using popular JPA frameworks in your Spring web apps (Hibernate/Eclipselink, etc) then this part should look familiar – Like any application we will need to create some objects to model our underlying data (the “M” in the MVC). For our simple application we will have three basic objects:



As you can see, we have three simple objects in our model, Resume, ResumePage, Section (we will just use these objects to split our document down in to several sections/chapters). One of the advantages of using Document-oriented DBs is that as it is schema-less, objects can be added to the document in the future without affecting existing data.
We model these objects as simple POJOs, just like modelling entities in JPA, but there are a few simple annotations Spring-Data provides for us
Resume.java:

@Document
public class Resume {
      
       @Id
       private String id;
      
       private List<ResumePage> pages = new ArrayList<ResumePage>();
...


That’s it! We use the @Document and @Id annotation to indicate any object that we want to treat as a Document, and the ID. We only need to add these annotations on our Resume object, as in this case the Resume is our document, we do not want to store our pages or sections as individual documents in themselves.



Data Access Layer

Now we have our data model we need to create our Data Access layer, so we can easily perform CRUD updates on our documents.
Creating our Data Access Objects is incredibly simple using MongoDB’s MongoRepository, and we automatically get basic CRUD functionality by just extending that interface. In our example app, we only want CRUD functionality so we just create a basic Interface that extends MongoRepository:

@Transactional
public interface IResumeRepository extends MongoRepository<Resume, String>{}

Next, in our Service layer we will auto-wire our new Interface in to our service classes (this is normal Spring stuff, using the @Autowired annotation we are telling Spring to handle the dependency injection for this interface):

@Repository("profileService")
@Transactional
public class ProfileService{

       @Autowired
       private IResumeRepository resumeRepo;


This makes the CRUD functionality available in our Service class to perform common functions, such as loadResume (in this case, we are using the resume owner’s name as the ID for the documents):

public Resume get(String userName) {
       return resumeRepo.findOne(userName.toLowerCase());
}


Or createResume:

       public Boolean createResume(Resume r) {
              try {
                     // Insert to db
                     resumeRepo.save(r);
                     return true;

              } catch (Exception e) {
                     //log exceptions here!
                     return false;
              }
       }


By simply extending the MongoRepository Interface and then auto-wiring it into our Service classes, we have provided basic CRUD functionality through the MongoRepository API as well as ensuring that our service class is not tightly coupled with the DAO implementation. However, often applications will need custom queries beyond basic CRUD. This can also be simply achieved using the MongoTemplate class provided, for example:

Query query = new Query(where("id").is(“rob”));
Resume r = mongoTemplate.findOne("mycollection", query, Resume.class);

The above query will retrieve the Resume belonging to “Rob”. The Query object provides rich API for accessing and updating documents in your data store.



Spring Configuration

The final step of our integration is to configure the Spring beans to handle the data source properties.
The Spring configuration resides in the Application Context XML file (in our case, it’s a file named “applicationContext.xml” and can be found in src/main/resources/META-INF/spring/.
This file is used to declare some of the Spring beans (although not all beans will be declared in here – some beans are declared using annotations, such as our Service classes), for our MongoDB integration we need to include the following configuration:

       <!-- Mongo Configuration -->
       <mongo:repositories base-package="com.tmm.nosql.mongodb.repo" />
      
       <bean id="mongoTemplate" class="org.springframework.data.document.mongodb.MongoTemplate">
              <constructor-arg ref="mongoDbFactory" />
       </bean>
      
       <!-- local config -->
       <mongo:db-factory id="mongoDbFactory" dbname="resume_db" host="localhost" port="27017"/>


The first element of the config declares the name of the package that our Repositories are stored in (this is where the our DAO Repository lives) – we declare this so to enable the package to be scanned for relevant repository classes.
The second configuration element declares the Mongo Template bean (provided by the Spring Data library) and we declare that we want Spring to inject our MongoDbFactory bean using Constructor based Dependency Injection.
The final configuration option declares the MongoDbFactory that we will be injecting in to our MongoTemplate bean – here we need to define the database server and port name. The default port number is 27017, so unless you have altered from the standard MongoDB install and configuration then you should use these details.




Running the Application

Running Locally

To test the application, set up a Tomcat server within your Eclipse (IDE) and add the project to the server, start the server and navigate to http://localhost:8080/ and you should see a simple welcome page.

Running on CloudFoundry

Before running on CloudFoundry we need to make a very minor tweak to the configuration. Previously we had added the configuration option:

<mongo:db-factory id="mongoDbFactory" dbname="resume_db" host="localhost" port="27017"/>

As we are no longer running on localhost and want to bind these options to CloudFoundry’s services, we change this to:

<cloud:mongo-db-factory id="mongoDbFactory"/>

Simple enough again – we just declare our MongoDbFactory, and leave CloudFoundry to inject the required parameters.


The next step to deploying the application on CloudFoundry is to add a CloudFoundry server instance to your eclipse:
  • Open the “Servers” view in Eclipse (Window>Show View>Servers)
  • Right-click and select New>Server

  • Select VMWare > Cloud Foundry and then press the “Next” button
  • You will then have to enter your Cloud Foundry account information:



  • Complete your email and password information, leaving the URL as it is and select the Next button.
  • The final screen will give you the option to add the project to the server, add the server and press Finish



Now the Cloud Foundry server instance is setup within your IDE you need to configure the deployed application so you can bind it to the required services:
  • Double-click on your deployed project within the “Servers” view:


  • This will open the “Applications” page – you will notice in the bottom left had corner an empty box titled Services, 




  • Press the “Add Service” button to the top right of the Services panel:




  • The MongoDB service will now be listed in the Services box, now drag it across to the right to the “Application Services” section. The “Applications” panel should now appear something like this:



  • Press the “Start” button under the General tab, then watch the log as the application is started up on the CloudFoundry – there should be no errors reported
  • Now navigate to the URL you assigned to the application (this can be edited in the above panel under the “General” section


You now have a MongoDB powered NoSQL application running in the Cloud!

Hands On NoSQL - Integrating MongoDB & Spring MVC


Over the weekend, I took some time out of my side project to have a play with MongoDB. I was interested in looking at NoSQL and getting my head around some of the implementation details and had heard document oriented NoSQL DBs would be a good place to start.

So I stripped out the guts of a web app I have built, and dropped in a very simple domain model (the app just allows creation of resumes - I chose it as I wanted a model that made sense to use a document oriented DB rather than trying to crowbar in a model that is still relational) - then using Spring I looked at wiring all the MongoDB stuff. I was pleasantly suprised with how easy it was to drop it all in.

This also gave me a chance to finally play with CloudFoundry - I've had my beta account for a while now, but seeing as CF supports MongoDB and Spring/Java apps I figured this would be a perfect chance to test it out. Again, it was relatively easy to configure the app and CF to get the app up and running using the Clouds mongo DB service.

The other bit of experimentation I have done is rather than writing this up in a massive blog post, I have signed up for slideshare and uploaded a presentation with the details - you can check out the presentation embedded above - would love to hear feedback as to whether you prefer slideshows or traditional blog posts - for me its harder to get a lot of details in slides without over-crowding them, but then if its a very detailed walkthrough it can make for an over-long blog post.

As always, the complete source code for the app (Spring MVC web app with full mongoDB configuration, including config for both localhost and CloudFoundry deployment) is available here!