Monday, July 22, 2013

Spring data mongodb - Getting started


Spring provides a module called spring data mongodb which provides a wrapper of mongodb. It simplifies the life of a developer by providing default implementations for CRUD and allowing the developer to write queries and other interactions in a easier way.

What should you do to get started on Spring data mongodb:

Include the following in the pom.xml
       <properties>
              <java-version>1.6</java-version>
              <org.springframework-version>3.1.1.RELEASE</org.springframework-version>
              <spring.data.mongodb.version>1.0.0.RC1</spring.data.mongodb.version>
              <spring-data-commons-core>1.2.0.RELEASE</spring-data-commons-core>
       </properties>
       ...

       <dependency>
              <groupId>org.springframework.data</groupId>
              <artifactId>spring-data-mongodb</artifactId>
              <version>${spring.data.mongodb.version}</version>
       </dependency>
       ...

Create a new file called application.properties and place it in classpath.
# For Localhost
databaseName=lsDB
dbHost=localhost

Create a Java Annotation based configuration file
@Configuration
@PropertySource(value = "classpath:application.properties")
public class AppConfiguration {

       @Autowired
       Environment environment;

       @Bean
       public Mongo mongo() throws UnknownHostException {
              String dbHost = environment.getProperty("dbHost");
              return new Mongo(dbHost);
       }

       @Bean
       public MongoDbFactory mongoDbFactory() throws Exception {
              String databaseName = environment.getProperty("databaseName");
              return new SimpleMongoDbFactory(new Mongo(), databaseName);
       }

       @Bean
       public MongoTemplate mongoTemplate() throws Exception {
              return new MongoTemplate(mongoDbFactory());
       }

}

The above code reads the db name and host information from application.properties file and creates the factory and Mongo beans.
Update the spring context file with the following information
<beans xmlns="http://www.springframework.org/schema/beans"
...
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
...
http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd>


       <!-- Bean Configuration -->
       <bean id="appConfiguration" class="com.cv.framework.configuration.AppConfiguration"></bean>

You also might need to tell where your Spring mongo repositories is located (i.e., the package)
       <!-- Mongodb Configurations -->
       <mongo:repositories base-package="com.cv.ls.mongorepository"
              mongo-template-ref="mongoTemplate" />

What is Spring Mongo Repository.
Mongo Repository in spring is actually an interface file that wraps lot of information such as CRUD and query implementation. The developer need to write only the interface and the implementation would be provided by the container.

package com.cv.ls.mongorepository;

@Repository
public interface StudentRepository extends  MongoRepository<Student, String>{
                public List<Student> findByFirstNameLike(String firstName);
                public List<Student> findByUsnLike(String usn);
                public List<Student> findByRollNumberLike(String rollNumber);
}

Note:
- @Repository indicates that this is a spring data mongo repository file.
- the interface need to extend from MongoRepository interface where all the method definitions such as save, findAll, findOne(id), delete methods are present.

You can see that we have created some custom methods such as

public List<Student> findByFirstNameLike(String firstName);

Note that these are only method definitions (interface methods).

Thats it !!!, You just need to tell what you want, not how do you do it. The container implementation takes care low level tasks such as getting the connection, executing the query, getting the results, iterating it and converting into list of student objects.

Now u need to use this Repository in the service class.

@Service
public class StudentService {
      
       @Autowired
       StudentRepository studentRepository;
      
       public Student save(Student student) {
              Student updatedStudent = studentRepository.save(student);
              return updatedStudent;
       }

       public Student find(String id) {
              return studentRepository.findOne(id);
       }
       public List<Student> findAll() {
              return studentRepository.findAll();
       }
      
       public void delete(String id) {
              studentRepository.delete(id);
       }

       public List<Student> searchStudentsForCriteria(StudentSearchCriteria studentSearchCriteria) {
              if(!studentSearchCriteria.getFirstName().equals("")) {
                     String firstName = studentSearchCriteria.getFirstName();
                     List<Student> students = studentRepository.findByFirstNameLike(firstName);
                     logger.info("Students obtained : " + students);
                     return students;
              }
              return null;
       }
      
}

Note:

- In the service class, first autowire the repository object. and invoke the methods accordingly.
- Note that we have not created any method called save or delete, but still you are able to invoke it, yep these comes for free - dont you like Spring data mongodb.

Coool, Now you can create the server implementations in a very fast manner  :-)

Sunday, July 21, 2013

Backbone custom events on model attribute change



In this article we are going to see how to handle custom events (i.e., when a model's value is changed, it should trigger an event.

Lets create a view called MessageView, it is attached to a model called MessageModel. Whenever anything happens on the web application, say an employee is saved successfully or there is an error saving an employee, it will update the messageModel.

In our scenario, whenever any attribute's value on MessageModel is changed, the view content should be changed.

       var Message = Backbone.Model.extend({
              defaults : {
                     message : "",
                     messageDetails : "",
                     messageType : ""
              },
       });

       var MessageView = Backbone.View.extend({
              el : '#message',
              initialize : function() {
                     this.model.on('change', this.render, this);
              },
              render : function() {
                     var templatewithMessage = _.template(MessageTemplate, this.model
                                  .toJSON());
                     $(this.el).html(templatewithMessage);
              }
       });


In this code, MessageTemplate is a template explained in the previous articles.

this.model.on('change') starts listening for any change events on this model and when someone changes an attribute in messageModel, it will fire, its corresponding function in our case, render method.

Hence the above code displays / updates the message in the message Bar. The message bar is nothing but a div represented by the id "message".

Event handling backbone view


Include the following content in a html file.

<div id="nameDiv">
       <p> My name is : </p> <input type="text" id="txtName"> <br>
       <button id="btnChangeName"> Change Name</button>
</div>


Create a view and include the below content.
var StudentView = Backbone.View.extend({
       el: '#nameDiv',
       initialize: function() {
              console.log('this is sort of a constructor');
              this.render();
       },
       events : {
              'click #btnChangeName' : 'changeName'
       },
       changeName : function() {
              alert('Going to change name');
       },
      
       render: function() {
              console.log('I am going to render');
              this.model = new Student();
              $('#txtName').val(this.model.get('name'));
       }
});


The events attribute in the above code contains the code for handlign the button click events. 

Note that the view is mapped to the div called nameDiv and it will handle only events or operations related to this div alone. This covers all the elements inside this div (i.e., text box and button inside this div). 

Simple !!! No more cluttering the html code with event handling code.



Backbone view meets template

View meets templates

Existing model:
var Student = Backbone.Model.extend({
       defaults : {
              name : 'Ram',
              age : 22,
              score : 100
       }
}
Create a new inline template using the template attribute.
template: _.template("My name is  : <%= name %>  "),

Use this template using the below statement.

this.template(this.model.toJSON())

The above method this.template gets the dom content. The function model.toJSON() gets the model values in a json format. Finally it passes the model value to the template, the template attribute "name" will get replaced with the value present in the mode.
Full View code:

var StudentView = Backbone.View.extend({
       tagName: 'p',
       class: 'headClass',
       id: 'sViewId',
       template: _.template("My name is  : <%= name %>  "),
       initialize: function() {
              console.log('this is sort of a constructor');
              this.render();
       },
       render: function() {
              console.log('I am going to render');
              this.model = new Student();
              $(document.body).html(this.$el.html(this.template(this.model.toJSON())));
       }
});

var studentView = new StudentView();

Well, it is easy since the template content contains less code, but as the template code gets bigger and more template gets added, this becomes cumbersome to maintain.

So it would be great if the template code is still present in a separate file. This is called external templates.
Well, what do we need to do in order to create a new template.

This can be done by moving the template code to a script tag in a js file
<script id="nameTemplate" type="text/template" >
              <b>My name is  : </b> <%= name %>              
</script>
Modify the existing template to
              template: '#nameTemplate',
              var template = _.template(this.template());
              this.$el.html(this.template(this.model.toJSON()));



Binding View with model

This article helps you to create a new View, bind it to a Model and display it in the html page.

Create a new model, say StudentModel

var Student = Backbone.Model.extend({
       defaults : {
              name : 'Ram',
              age : 22,
              score : 100
       }
}); 

Create a new View, say StudentView

var StudentView = Backbone.View.extend({
       // tagName: 'p',
       class: 'headClass',
       id: 'sViewId',
       initialize: function() {
              console.log('this is sort of a constructor');
              this.render();
       },
       render: function() {
              console.log('I am going to render');
              $(document.body).html(this.$el.html("I am a new student :-)"));
       }
});
In the above code, this.el will return the html code that this view has generated, in this case, it simple creates a div element.




If you say studentView.$el, then it returns jquery object of the el (which means you can run you jquery methods using this $el.
if you uncomment the tagName attribute in the StudentView and run the same thing again, you can see that the div is replaced with <p> tag. 

Hence the view is mapped to a html element, if you leave it without defining it, then it simply creates a empty div element - you can define whatever you want, <p>, <ul> <li> etc.,

Note that the render method is automatically called, actually we are calling it from the initialize method. initialize() is actually a constructor which will be called everytime you create an object of the view. This applies to all Backbone objects such as Model, View etc.,

Ok, lets bind the value from the model to the dom element <p>, hmmm, that's simple. 

var Student = Backbone.Model.extend({
       defaults : {
              name : 'Ram',
              age : 22,
              score : 100
       }
});

var StudentView = Backbone.View.extend({
       tagName: 'p',
       class: 'headClass',
       id: 'sViewId',
       initialize: function() {
              console.log('this is sort of a constructor');
              this.model = new Student();
              this.render();
       },
       render: function() {
              console.log('I am going to render');
              $(document.body).html(this.$el.html('I am  ' + this.model.get('name') + ' - my age is : ' + this.model.get('age')));
       }
});

The render method takes the template, normally picks the data and renders it.


Ok, lets see more in the next article.