Saturday, March 23, 2013

My First Xtend Program

Hi all! This is Ross again. For those who don't know, Oracle created a spinoff of Java called Xtend. It was created to make JVM prgramming easier. After much trial-and-error, I got Xtend to work on my Windows 8 laptop. Right now, as far as I know Xtend in available only for Eclipse. If I find a NetBeans version, I'll post about it. Eclipse translates Xtend code into Java when building the project. I'm using Morphia and MongoDB, and I assume you have their JARs in the appropriate JRE directory.

First of all, you can find Xtend at http://www.eclipse.org/xtend/ . Click on the "Download" button, then choose the "Full Eclipse" most appropriate for your operating system. If you choose a Windows version, it will come as a Zip folder. I'm redoing everything for the purpose of this blog. For this purpose, I'm extracting the Zip to C:\Xtend . You will find the Eclipse application in the "eclipse" subdirectory.

Next, I created a Java Project called "test1". When I created it, I added the Xtend library to its classpath. Next, I added an Xtend class called "Name" in the new package "org.main". Here is the code for the Name class:



package org.main

import com.google.code.morphia.annotations.Entity
import com.google.code.morphia.annotations.Id
import com.google.code.morphia.annotations.Serialized

@Entity("names")
@Data public class Name {

@Id
String id

@Serialized("firstName")
String firstName

@Serialized("lastName")
String lastName

public new(String first, String last) {
_id = null
_firstName = first
_lastName = last
}

public new() {
_id = ""
_firstName = ""
_lastName = ""
}

}



The "Entity", "Id" and "Serialized" annotations are for MongoDB's and Morphia's benefit. The "Data" annotation tells the  Java generator to create a contructor, as well as getters and setters. The "new" methods are Xtend constructors. The underscores are necessary when using "@Data", as it also translates your members into private members with names prefixed by underscores.  The constructor with the empty argument list is so that Morphia can convert MongoDB objects to the Java class.  If we weren't using "@Data", this("default") would work instead of manually initializing the members to null strings.

Now, for the main attraction... the "main" method. I created an Xtend class named "Program" in the "org.main" package. Here is that entire class:


package org.main

import java.net.UnknownHostException
import java.util.Scanner
import com.mongodb.MongoClient
import com.mongodb.BasicDBObject
import com.google.code.morphia.Morphia

class Program {
def public static void main(String[] args) {
try {
var scanner = new Scanner(System::in)
print("First name: ")
var first = scanner.nextLine
print("Last name: ")
var last = scanner.nextLine

var client = new MongoClient
var db = client.getDB("xtend2")
var collection = db.getCollection("names")

var query = new BasicDBObject("firstName", first).append("lastName", last)
var count = collection.find(query).count

if (count > 0) {
println("That name is already on file.")
}
else {
println("Proceeding...")
var morphia = new Morphia
var name = new Name(first, last)
var jname = morphia.toDBObject(name)
collection.save(jname)
println("The new name was successfully added.")
}

var cursor = collection.find() // get the entire collection
var morphia = new Morphia().map(typeof(Name))
for (obj : cursor) {
var BasicDBObject basic = obj as BasicDBObject
var name = morphia.fromDBObject(typeof(Name), basic)
println(name.id + " : " + name.firstName + " " + name.lastName)
}

client.close

catch(UnknownHostException e) {
println("Error: " + e.message)
}

}


I know you might be scratching your head, thinking "What kind of Java is this?". This first thing you might notice is there aren't and semicolons. You usually don't need then in Xtend. Also, instead of System.in, you use System::in . Console output has been greatly simplified; all you need are print and println. Empty method parentheses can be omitted. Unlike Java, Xtend can handle implicit type determination. In Xtend, you send class type arguments using typeof. Explicit casting is also done differently. You can see an example in the above  obj as BasicDBObject . Lastly, since I used the "Data" annotation earlier, I can access the members of the "Name" class as though they were public.

What does this program do? It asks for your name, then checks it against the database. If there is no match,your name gets added. Lastly, the updated document list is displayed.

There are other differences between Xtend and Java, but I won't go into them here. If you need more clarification of my project, e-mail me at euric.reiks@comcast.net . Thanks for reading this post, and God be with you!

Thursday, March 14, 2013

Java MVC with MongoDB and Morphia part 3

Hi, this is Ross. I made some changes to my name list website, and I thought I should share the changes.

The first thing I did was split the method in my service class. The code that added the data is now separate from the code that generates the name list. I also added logic that prevents exact duplication of entries. Here is the new AddName method:


        private static String database = "mvcmongo3";
        private static String collection = "names";
        
        public static String AddName(String first, String last)
            throws UnknownHostException {
            
            MongoClient client = new MongoClient();
            DB db = client.getDB(database);
            DBCollection coll = db.getCollection(collection);
            Name name = new Name();
            name.setFirstName(first);
            name.setLastName(last);
           
            BasicDBObject query = 
                new BasicDBObject("firstName", first).append("lastName", last);
            int count = coll.find(query).count();
            String message = null;
            if (count > 0) {
                message = first + " " + last + " is already on file";
            } else {
                message = first + " " + last + " is now on file";
                Morphia morphia = new Morphia();
                DBObject jname = morphia.toDBObject(name);
                coll.save(jname);
            }
            client.close();
            return message;
            
        }

As you can see, I build a JSON object with just the entered data, called "query".  

int count = coll.find(query).count();

counts the number of documents whose data matches the input. As you can see, this version of AddName returns a string that reports the results of that query. If no match is found, the input is added to the document collection. Here is the new function:


        public static ArrayList<Name> ListNames()
            throws UnknownHostException {
        
            MongoClient client = new MongoClient();
            DB db = client.getDB(database);
            DBCollection coll = db.getCollection(collection);
            DBCursor cursor = coll.find();
            ArrayList<Name> list = new ArrayList<Name>();
            for (DBObject b : cursor) {
                Morphia morphia2 = new Morphia().map(Name.class);
                BasicDBObject basic = (BasicDBObject)b;
                Name name2 = morphia2.fromDBObject(Name.class, basic);
                list.add(name2);
            }
            client.close();
            return list;
      }

As before, an argument-less query retrieves the entire collection. Morphia then translates each document into the Java class "Name", and adds the converted object to the list. As you can guess, I changed the controller, too...


    @Override
     protected ModelAndView onSubmit(
     HttpServletRequest request, 
     HttpServletResponse response, 
     Object command, 
     BindException errors) throws Exception {
         HttpSession session = request.getSession(true);
         Name name = (Name) command;
         ModelAndView mv = new ModelAndView(getSuccessView());
         mv.addObject("message", nameService.AddName(name.getFirstName(),
                 name.getLastName()));
     //    mv.addObject("nameList", nameService.ListNames());
       session.setAttribute("nameList", nameService.ListNames());
     //Do something...
     return mv;
     }

Now I create a session. Instead of adding the name list directly to the ModelAndView, I add it to the session. I made that change to make it easier for JSP to find the list. My code adds the string from AddName the old way. I didn't change the form view, but I did change the "success" view by creating success2View.jsp. I changed a controller's constructor's line to

setSuccessView("success2View"); 

I also added the following namespace to the controller:

import javax.servlet.http.HttpSession;

Here is the new view...


<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@page session="true" import="java.util.ArrayList, controller.*" %>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Success Page</title>
    </head>
    <body>
        <p>${message}</p>
        <h1>Name List</h1>
        
        <ul>
            <% for (Name name : (ArrayList<Name>)session.getAttribute("nameList")) { %>
            <li><%= name.getFirstName() %>&nbsp;<%= name.getLastName() %></li>
            <% } %>
        </ul>
    </body>
</html>

You can see I use standard JSP code now instead of JSTL. I retrieve the "nameList" session variable and cast it to ArrayList<Name>. The new view now shows whether or not the entered name was added to the database, as well as all the names in the collection as before. Note I use the getters in the Name class. I also import the ArrayList class in addition to the Name class. Note that it's more obvious what's going on. That "for" syntax is Java's "for-each". 

That concludes the changes I made. I plan on writing a more elaborate website using this stack. If I succeed, you'll probably hear about it. Thanks for reading and God bless!












Friday, March 8, 2013

Using PHP With MongoDB on Windows 8

In this post, we'll discuss getting PHP to run with MongoDB on Windows. I'll assume you already have MongoDB up and running. You might need a different copy of PHP, though.

 I made a folder called "PHP_5_4_12" first. Then, I went to http://windows.php.net/download/ and downloaded the "VC9 x86 Thread Safe" Zip file. I unpacked the Zip to C:\PHP_5_4_12. Then I went to the IIS manager through Control Panel. I went to Handler Mappings, and clicked on "Add Module Mapping". I entered "*.php" (minus the quotes) for the Request path, selected FastCgiModule, and named it PHP. For the executable, I entered "C:\PHP_5_4_12\php-cgi.exe" minus the quotes.  For the request restrictions, I selected "File Or Folder". I agreed to have IIS add this handler to the FastCGI list.

The next step was getting the MongoDB PHP drivers. I downloaded the latest version (it was 1.3.2 RC 1when I did this) from https://github.com/mongodb/mongo-php-driver/downloads . I then unpacked the Zip and copied the php_mongo-1.3.2RC1-5.4-vc9.dll DLL to C:\PHP_5_4_12\ext. Also, I right-clicked on the new copy, went into Properties and unblocked the file. 

The next step was configuring PHP. I went into the php.ini (copy one of the candidate INIs and rename the copy if you don't have a file with that specific name). I removed the semicolon from the

 ;extension_dir = "ext"

entry. That tells PHP where to find extension DLLs. The last change I had to make was go into the extension list and add the following to the bottom of the list prior to the MIBS list:

extension=php_mongo-1.3.2RC1-5.4-vc9.dll

Use the exact name of the DLL file you copied into the "ext" directory. I saved my changes.

In my case, I have a MongoDB database called "mvcmongo3" with a collection of names called "names". To test my work, I created a script file called "mongo2.php", which consisted of:


<?php

class SearchName {
  public $firstName;
  public $lastName;

  public function SearchName($first, $last)
  {
    $this->firstName = $first;
    $this->lastName = $last;
  }
}

class Name extends SearchName {
  public $_id;
#  public $firstName;
#  public $lastName;

  public function Name($obj)
  {
    $this->_id = $obj['_id'];
    $this->firstName = $obj['firstName'];
    $this->lastName = $obj['lastName'];
  }


}



$m = new MongoClient();
$db = $m->mvcmongo3;
$col = $db->names;
$cursor = $col->find();

foreach ($cursor as $obj) {
  $nameObject = new Name($obj);  
  print "$nameObject->_id : $nameObject->firstName $nameObject->lastName <br />";  
}

echo "Found " . $cursor->count() . " names.<br />";

$name = new SearchName("Ross", "Albertson");
print "Found " . $col->find($name)->count() . " matches <br />";

$cursor2 = $col->find($name);

foreach ($cursor2 as $obj) {
  $nameObject = new Name($obj);  
  print "$nameObject->_id : $nameObject->firstName $nameObject->lastName <br />";  
}

?>

Running the script in C:\inetpub\wwwroot, I got the following results....

513772c6e037b778819b159c : Ross Albertson
51377310e037b778819b159d : David Albertson
5137732fe037b778819b159e : Ross Babcock Jr.
513774d2e037b778819b159f : David Acker
51377568e037b778819b15a0 : David Johnson
513777e4e037b778819b15a1 : Sara Werckle
Found 6 names.
Found 1 matches 
513772c6e037b778819b159c : Ross Albertson 

$col->find() retrieved a list of all of the names; $col->find($name) retrieved all the documents with a first name of "Ross" and a last name of "Albertson". The funny-looking string are the document IDs. I think $col->save($name); will store the name into that MongoDB collection, given my naming convention. Given that, try experimenting with php_mongo.  


Monday, March 4, 2013

Java MVC Forms With Morphia and MongoDB part 2

Welcome back! We're going to finish our Java Web application. We're going to create two classes and two page layouts.

Go into NetBeans and create a Java class called NameService in a new package called "service". It's going to have a single method called "AddName", which will take the user input and add it to the document collection. It will also retrieve the whole collection and convert it into an ArrayList. The data will be stuffed into a Name object, be converted into JSON, then stored in MongoDB. Morphia will be handling the conversion of the data between the Name class and JSON. We will call the database "mvcmongo1", and (as I said before), call the collection "names". Here are the namespaces we'll need:


import controller.Name;
import java.util.ArrayList;
import com.mongodb.MongoClient;
import java.net.UnknownHostException;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.google.code.morphia.Morphia;
import com.mongodb.DBObject;
import com.mongodb.DBCursor;
import com.mongodb.BasicDBObject;

And here is the body of the NameService class:


    public static ArrayList<Name> AddName(String first, String last)
            throws UnknownHostException {
        MongoClient client = new MongoClient();
        DB db = client.getDB("mvcmongo1");
        DBCollection coll = db.getCollection("names");
        Name name = new Name();
  //      name.firstName = first;
  //      name.lastName = last;
        name.setFirstName(first);
        name.setLastName(last);
        Morphia morphia = new Morphia();
        DBObject jname = morphia.toDBObject(name);
        coll.save(jname);
        DBCursor cursor = coll.find();
        ArrayList<Name> list = new ArrayList<Name>();
        for (DBObject b : cursor) {
            Morphia morphia2 = new Morphia().map(Name.class);
            BasicDBObject basic = (BasicDBObject)b;
            Name name2 = morphia2.fromDBObject(Name.class, basic);
            list.add(name2);
        }
        return list;
    }

The next step is to create the controller. In Java MVC, a controller's name is capitalized, and the last part of the name must be "Controller". The first part of the name gets de-capitalized as the name of the .htm file the browser accesses.  In our case, we'll call our controller MainController, from which the compiler will generate a main.htm. Create a file of the type Spring Framework >> Simple Form Controller called "MainController", and put it in the "controller" package.

Uncomment the body of the constructor. Use the Name class for the CommandClass, and "name" for the command. That binds the Name class to the form, and the string "name" will be cross-referenced in the form. The constructor should now read as:

    public MainController() {
        //Initialize controller properties here or 
        //in the Web Application Context

        setCommandClass (Name.class);
        setCommandName("name");
        setSuccessView("successView");
        setFormView("formView");
    } 

We are using the defaults for the form view and the verification view ("successView"). Now, delete or comment out the doSubmitAction method and uncomment the onSubmit method. Now, change the body of the onSubmit method to


         Name name = (Name) command;
         ModelAndView mv = new ModelAndView(getSuccessView());
         mv.addObject("nameList", nameService.AddName(name.getFirstName(),
                 name.getLastName()));



Now, right-click and select "Fix Imports". You might need to change some values. The resulting list should contain


import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;

We're not quite done with the controller. The next step to to put the following at the head of the body of this class:


    private NameService nameService;
    
    public void setNameService(NameService nameService) {
        this.nameService = nameService;
    }

Fix the imports again and save the file. This code creates the nameService object for the onSubmit method. The next step is to configure the website. To do this, add the following bean to applicationContext.xml in the Web Pages\WEB-INF folder. Place it right under the "Beans" header node...

<bean name="nameService" class="service.NameService" />

Refer to that bean in dispatcher-servlet.xml right under the existing bean as follows:

<bean class="controller.MainController" p:nameService-ref="nameService"/>

The last thing to do is create the views in the Web Pages\WEB-INF\jsp folder. Right-click on that folder and select New >> JSP, then call the view "formView". Change the title of the page and the body of the <H1> tag to "Enter Your Name".  Now, under the <H1> tag, place the following:


<spring:nestedPath path="name">
        <form action="" method="post">
            <p>First Name:
            <spring:bind path="firstName">
                <input type="text" name="firstName">
            </spring:bind></p> 
          
            <p>Last Name:
            <spring:bind path="lastName">           
                <input type="text" name="lastName">
            </spring:bind></p>
        
            <p><input type="submit" value="OK"></p>
        </form>
</spring:nestedpath>

The nestedPath path is the same "name" as the "name" that is the command name in the controller. Each <spring:bind> binds that text field to a member in the Name class. Now for last step, the "success" view. Create another JSP file, this time with the name "successView". Change the title and the <H1> body to "Name List". Now, here is the where the JSTL comes in. At the line after the <H1> tag, place the following:


         <c:forEach var="name" items="${nameList}">
            <c:out default="nada" value="${name.firstName}"></c:out>&nbsp;
            <c:out default="nada" value="${name.lastName}"></c:out><br />
         </c:forEach>

The nameList object was created by the controller and sent to this view by its call to the addObject method. This code loops through the ArrayList created by the AddName method and displays the element's contents.

The last step is to right-click on the project's root node and select Properties. Click on "Run" on the left side of the Properties window, and type "main.htm" in the relative URL textbox. Save the changes, then run the application. If all goes well, you should see a form with two textboxes. Every name you have submitted should be in a list on the submission page.  You might need to add the following to the top of the successView file:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

That concludes the tutorial.





Friday, March 1, 2013

Java MVC Forms With MongoDB And Morphia, part 1

I assume you have MongoDB up and running, and that you have a functional copy of NetBeans.

The first thing we need to do is download the necessary JAR files. You can find a MongoDB driver for Java at https://github.com/mongodb/mongo-java-driver/downloads. Get the most recent version. Morphia will be used to interact between Java and MongoDB. You can find the JARs at http://code.google.com/p/morphia/downloads/list. You will only need Morphia itself for this example. You will find life easier if you copy the two JARs to your JDK. In Windows, that will most likely be in C:\Program Files\Java. Go to your JDK folder, then put the JARs in the \jre\lib\ext subdirectory.

Now, start up NetBeans, and start a new project. Choose "Java Web" > "Web Application", then click Next. Give the project a name, then press Next. Choose the defaults on the next screen, then select the Spring MVC option on the one after. We will want JSTL. Now we're finished with that step.

Run the application as is. You should get a web page that says "Hello! This is the default welcome page for a Spring Web MVC project." as the first line. index.htm is the default home page; we will change that later.

The next step is creating the model class. In this example, we'll just be storing people's names, with the first and last names as separate fields. Create a Java class ("Java" > "Java class") called "Name" under a package called "controller". Add the following line between the "package" and "class" lines:

import com.google.code.morphia.annotations.*;

Next, put the following line right before the class declaration:

@Entity("names")

That annotation tags this class as a Morphia Entity. "names" is the name of the document collection. Now, start the class body as follows:

    @Id
    String id;
   
    @Serialized("firstName")
    String firstName;
   
    @Serialized("lastName")
    String lastName;


The @Id annotation is needed to designate the field as the document ID. The @Serialized annotations include those fields in the documents. They also determine their field names in the JSON that actually get stored.  Now, right-click on the code window, select "Insert Code", then select "getter and setter". Click on the class's checkbox and OK the change. Your code should now look like:

package controller;
/**
 *
 * @author Ross
 */
import com.google.code.morphia.annotations.*;

@Entity("names")
public class Name {
    @Id
    String id;
   
    @Serialized("firstName")
    String firstName;
   
    @Serialized("lastName")
    String lastName;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
}


Getters and setters are necessary for the JSP form to access this class correctly.
That's the first part. In the next entry, we will finish the Java code.



Introduction

Hi, all! This is Ross Albertson and welcome to my blog. I've created blogs about specific issues, but I thought I would make one for random programming issues. I plan to issue my first entry soon. Lately my focus has been on NoSQL database systems... in particular, document-based systems. I might talk about other things as well. The first thing I'm thinking of tackling is Java 7 MVC form processing using NetBeans, Morphia and MongoDB. My e-mail address is euric.reiks@comcast.net; feel free to contact me with comments, questions, or topics to explore.