Friday, August 30, 2013

Spring Data, Mongo and Play 2.1

Ok we will go back in this post to Java and the idea for today is to integrate Mongo + Spring Data, with a great framework, called Play(version will be 2.1)

Of course, we talk about Spring, it means we start with some configurations...
Because we are working with play, please forget for a moment about Maven and we have two solutions for adding dependecies
1.Create a lib folder and add every jar you want
                              or
2.Update appDependencies from Project/Build.scala file in a Maven style
GroupArtifactVersion
"org.springframework""spring-core""3.2.2.RELEASE"

import sbt._
import Keys._
import play.Project._

object ApplicationBuild extends Build {

  val appName         = "MongoPlayExample"
  val appVersion      = "1.0-SNAPSHOT"

  val appDependencies = Seq(
    // Add your project dependencies here,
    "org.springframework" % "spring-core" % "3.2.2.RELEASE",
    "org.springframework" % "spring-context" % "3.2.2.RELEASE",
    "org.mongodb" % "mongo-java-driver" % "2.11.0",
    "org.springframework.data" % "spring-data-mongodb" % "1.2.0.RELEASE",
    "cglib" % "cglib" % "2.2.2",
    javaCore,
    javaJdbc,
    javaEbean
  )

  val main = play.Project(appName, appVersion, appDependencies).settings(
    // Add your own project settings here      
  )

}
Now because we don't really like today old Spring xml configurations, we have to create a SpringConfiguration class annotated with @ Configuration and a Global class for accessing ApplicationContext

 **Global.java
public class Global extends GlobalSettings{

    private static ApplicationContext applicationContext;

    @Override
    public void onStart(Application application) {
     System.out.println("on start");
        applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);
    }
    public static ApplicationContext getContext() {
        if (applicationContext == null) {
            throw new IllegalStateException("application context is not initialized");
        }
        return applicationContext;
    }
}
**SpringConfiguration.java
@Configuration
public class SpringConfiguration {
 
 public @Bean
 MongoDbFactory mongoDbFactory() throws Exception {
  return new SimpleMongoDbFactory(new MongoClient(), "PlayDB");
 }
 
 public @Bean(name="mongoTemplate")
 MongoTemplate mongoTemplate() throws Exception {
 
  MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory());

  return mongoTemplate;
 
 }
 
 public @Bean(name="repositoryUser")
 RepositoryUser repositoryUser() throws Exception
 {
  return new RepositoryUserImpl(mongoTemplate());
 }
}
As you can see we use some Spring Data features for connectiong to a Mongo Database and we define the beans in the code not in xml files.

After finishing the configuration part, the next step, is to create an entity(document) and a repository layer to show how to work with spring data mongo operations.

**User class
@Document(collection = "users")
public class User {
 
 @Id
 private String id;
 
 private String username;
 
 private String password;
 
 private String role;

 public User(String username, String password, String role) {
  super();
  this.username = username;
  this.password = password;
  this.role = role;
 }
       /*please implement getters and setters*/


**RepositoryUser interface
public interface RepositoryUser {

 List getAll();
 void save(User user);
 void delete(User user);
 User findById(String id);
}


**RepositoryUserImpl class
public class RepositoryUserImpl implements RepositoryUser {

 private MongoOperations mongoOperations;
 
 public RepositoryUserImpl(MongoOperations mongoOperations)
 {
  this.mongoOperations = mongoOperations;
 }
 @Override
 public List getAll() {
  // TODO Auto-generated method stub
  return mongoOperations.findAll(User.class);
 }

 @Override
 public void save(User user) {
  // TODO Auto-generated method stub
  mongoOperations.save(user);
 }

 @Override
 public void delete(User user) {
  // TODO Auto-generated method stub

 }

 @Override
 public User findById(String id) {
  // TODO Auto-generated method stub
  return null;
 }

}


Using Spring Data with Mongo offers the possibility to work with entities like any other ORM framework for relational databses like Hibernate for example...

** Controller for integrating our beans
public class Application extends Controller {
 
 private RepositoryUser repositoryUser=(RepositoryUser) Global.getContext().getBean("repositoryUser");
    
 public Result index() {
        //return ok(views.html.index.render("Your new application is ready."));
     //this.repositoryUser.save(new User("ionel", "abcd", "user"));
     return ok(this.repositoryUser.getAll().get(0).toString());
    }
  
}


And this is it! I created a short but strong example working with Spring Data, Mongo DB and Play Framework. In the future I hope we will come back to Play because it deserves many articles and a huge space in software development.I think Play can compete in the future with Wicket or Spring without any problems.Good luck! MVC, java, dependency injection, mongo, spring, spring data, play framework, play 2.1, play GlobalSettings

Friday, August 23, 2013

@Ajax.Actionlink ASP MVC

This HTML helper offers the possibility to create ajax requests by writing less code than in a jquery classical way. I spent some time trying to integrate this pretty feature in my application and I want to share with you how tot this very quickly. So, I want to show how set the Http method, the parameters and other options.

 First I will present an action from the previous tutorial(where I used mongo). The action provides details for a book(attributes name and publisher) and is returning a JSON if the book exists, else just simple message.

        [HttpPost]
        public ActionResult Details(string id)
        {
            try
            {
                var book = repBook.findById(id);

                return Json(book);
            }
            catch(Exception e)
            {
                return Content("not found");
            }
        }
Then let's try to create an ajax request in Index view to display some information about a book. Very simple...
@model IEnumerable

@{
    ViewBag.Title = "Index";
}

Index

@Html.ActionLink("Create New", "Create")
@foreach (var item in Model) { }
@Html.DisplayNameFor(model => model.name) @Html.DisplayNameFor(model => model.publisher)
@Html.DisplayFor(modelItem => item.name) @Html.DisplayFor(modelItem => item.publisher) @Html.ActionLink("Edit", "Edit", new { id=item.Id }) | @*@Html.ActionLink("Details", "Details", new { id=item.Id }) |*@ @Html.ActionLink("Delete", "Delete", new { id=item.Id }) @{ var options = new AjaxOptions { UpdateTargetId = item.name, InsertionMode = InsertionMode.Replace, OnSuccess = "success(data," + item.name + ")", OnFailure = "failure()", HttpMethod = "Post" }; } @Ajax.ActionLink("Ajax details","Details",new {id="fdsf"},options)
@section scripts{ }
And that's all! ASP.NET MVC, .Net, MVC, HTML helpers, Ajax, @Ajax.ActionLink, JSON, JsonResult

Thursday, August 22, 2013

ASP.NET and Mongo Databases

In this post I will try to show you how to use MongoDB in your .Net MVC project and how to simplify your life in repositories development, by using MongoRepository NuGet. 

  1. Install NuGet Packages for Mongo usage

Go to Manage NuGet Packages and search mongo, then install Official MongoDB driver and MongoRepository



Before starting to write code, please look in your web.config file and set you database name:
  
    
    
    
  

2. Create some entities...

**Author entity

    public class Author:Entity
    {
        [Required]
        //[RegularExpression(@"([a-zA-Z\d]+[\w\d]*|)[a-zA-Z]+[\w\d.]*", ErrorMessage = "Invalid name")]
        public string name { get; set; }
        public HashSet books { get; set; }

        public Author()
        {
            this.books=new HashSet();
        }

        public override int GetHashCode()
        {
            return this.name.GetHashCode()*2;
        }

        public override bool Equals(object obj)
        {
            if (obj is Author)
            {
                Author a = (Author)obj;
                if (a.Id == this.Id)
                {
                    return true;
                }
            }

            return false;
        }

        public override string ToString()
        {
            return this.Id + " " + this.name;
        }
    }
**Book entity
    public class Book:Entity
    {
        public string name { get; set; }
        public string publisher { get; set; }
        public List authors { get; set; }

        public Book()
        {
            this.authors = new List();
        }

        public override int GetHashCode()
        {
            return this.name.GetHashCode() * 2;
        }

        public override bool Equals(object obj)
        {
            if (obj is Book)
            {
                Book b = (Book)obj;
                if (b.Id == this.Id)
                {
                    return true;
                }
            }

            return false;
        }

        public override string ToString()
        {
            return this.Id + " " + this.name;
        }
    }
1) Note that I created a many-to-many relationship between entities

2) Our entities extends Entity class and we do this because that's how MongoRepository works and this helps for automatically creating ObjectId for every document

3.Repository layer

I'm not gone show you the entire code for both repositories because the idea is the same

**IRepositoryAuthor interface
    public interface IRepositoryAuthor
    {
        IList getAll();
        void save(Author author);
        void update(Author author);
        void delete(Author author);
        Author findById(string id);
        void deleteAll();
    }
**RepositoryAuthor implementation
    public class RepositoryAuthor:IRepositoryAuthor
    {
        private MongoRepository repository;

        public RepositoryAuthor()
        {
            this.repository = new MongoRepository();
        }

        public IList getAll()
        {
            return repository.ToList();
        }

        public void save(Models.Author author)
        {
            this.repository.Add(author);
        }

        public void update(Models.Author author)
        {
            this.repository.Update(author);
        }

        public void delete(Models.Author author)
        {
            repository.Delete(author.Id);
        }

        public Models.Author findById(string id)
        {
            return repository.GetById(id);
        }

        public void deleteAll()
        {
            repository.DeleteAll();
        }
    }
I created a MongoRepository object which helps us to perfom CRUD operations.This is the idea of MongoRepository NuGet and I think is very useful

3.Last thing is to create a controller which use the repository

  I agree that this not the best approach to use repositories in controllers, but this is just a basic example

**Controller class
    public class AuthorController : Controller
    {
        //
        // GET: /Author/ 
        private IRepositoryAuthor repAuthor;
        private IRepositoryBook repBook;

        public AuthorController(IRepositoryAuthor repAuthor,IRepositoryBook repBook)
        {
            this.repAuthor = repAuthor;
            this.repBook = repBook;
        }

        public ActionResult Index()
        {
            return View(repAuthor.getAll());
        }

        //
        // GET: /Author/Details/5

        public ActionResult Details(string id)
        {
            var author=repAuthor.findById(id);
            if (author == null)
            {
                return HttpNotFound();
            }
            return View(author);
        }

        //
        // GET: /Author/Create

        public ActionResult Create()
        {
            ViewBag.Books = repBook.getAll().Select(i=>new SelectListItem { 
                Value=i.Id,
                Text=i.name
            });
            return View();
        }

        //
        // POST: /Author/Create

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create(Author author,string[] books)
        {
            try
            {
                // TODO: Add insert logic here
                ViewBag.Books = repBook.getAll().Select(i => new SelectListItem
                {
                    Value = i.Id,
                    Text = i.name
                });

                ModelState.Remove("books");

                if (ModelState.IsValid)
                {
                    HashSet author_books = new HashSet();

                    if (books != null)
                    {
                        foreach (var id in books)
                        {
                            var book = repBook.findById(id);
                            if (book != null)
                            {
                                author_books.Add(book);
                            }
                        }
                    }

                    author.books = author_books;
                    repAuthor.save(author);

                    return RedirectToAction("Index");
                }

                return View(author);
            }
            catch
            {
                return View(author);
            }
        }

        //
        // GET: /Author/Edit/5

        public ActionResult Edit(int id)
        {
            return View();
        }

        //
        // POST: /Author/Edit/5

        [HttpPost]
        public ActionResult Edit(int id, FormCollection collection)
        {
            try
            {
                // TODO: Add update logic here

                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }

        //
        // GET: /Author/Delete/5

        public ActionResult Delete(string id)
        {
            var author = repAuthor.findById(id);
            if (author == null)
            {
                return HttpNotFound();
            }
            return View(author);
        }

        //
        // POST: /Author/Delete/5

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Delete(Author author)
        {
            try
            {
                // TODO: Add delete logic here
                repAuthor.delete(author);

                return RedirectToAction("Index");
            }
            catch
            {
                return View(author);
            }
        }
    }
The views and the controllers are the same as when we work with enity framework or nhibernate. The only problem is that we can't use scaffolding so quickly, but we can generate first controllers, update the actions and then create views from templates.  And for views I will give you an example of how it looks the HTML for Create page:
@model MongoMVC.Models.Author

@{
    ViewBag.Title = "Create";
}

Create

@using (Html.BeginForm()) { @Html.AntiForgeryToken() @Html.ValidationSummary(true)
Author
@Html.LabelFor(model => model.name)
@Html.EditorFor(model => model.name) @Html.ValidationMessageFor(model => model.name)
@Html.Label("books") @* @{ var items=Model.books.Select(i => new SelectListItem { Value = i.Id, Text = i.name }); }*@ @Html.ListBox("Books",null, new { style="width:70px"})
}
ASP.NET MVC, .Net, MVC, HTML helpers, ASP.MVC Forms, Models, SelectList, Mongo Database, NoSql, MongoRepository, RedirectToAction