Node for the Java Developer - newgeekorder/TechWiki GitHub Wiki
Being a non-dogmatic Java Developer for over 10 years that also faced the scorn of purists for using groovy and jvm languages it is not hard to appreciate the light weight speed of Nodejs but also have concerns about reliable implementations that need to be addressed
Node to me is two essential things
- it is a means to use javascript on the server side
- it is not mandatory however node gains it's efficiency by using non-blocking I/O and asynchronous events
| maven respoisotires of jar's and dependencies | Node uses npm modules and the version dependencies can be managed with bower|
All of the traditional ide's support Node
- Eclipse – This should be an easy win if you use it for Java. Just install the node.js extensions.
- JetBrains IntelliJ IDEA – has excellent node and web technologies support
- Microsoft Visual Studio – The new Microsoft has added native support for it inside of Visual Studio.
- SublimeText 2 – A no frills text editor that is gaining in popularity among developers for its lightweight approach.
Create a simple REST service in both the Java EE and Node.js programming languages. The REST service will simply read information from a MongoDB database and return the results to the requestor. Covering the installation and configuration of the Java application server and MongoDB database are not in scope for this article.
Creating our Java application Step 1: The pom.xml file
For the sample application, called restexample, I will be using the JBoss EAP Application Server. The first thing we want to do is configure our pom.xml file for dependency management using the Maven build system. Below is the pom.xml file that includes the dependencies that I will be using for the restexample application:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>restexample</groupId>
<artifactId>restexample</artifactId>
<packaging>war</packaging>
<version>1.0</version>
<name>restexample</name>
<repositories>
<repository>
<id>eap</id>
<url>http://maven.repository.redhat.com/techpreview/all</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>eap</id>
<url>http://maven.repository.redhat.com/techpreview/all</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.6</maven.compiler.source>
<maven.compiler.target>1.6</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.jboss.spec</groupId>
<artifactId>jboss-javaee-6.0</artifactId>
<version>3.0.2.Final-redhat-4</version>
<type>pom</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>2.9.1</version>
</dependency>
</dependencies>
</project>
Step 2: Creating the beans.xml file and setting our servlet mapping
As part of the sample application, we will be using CDI (Context Dependency Injection) for our database access class. According to the official CDI specification, an application that makes use of CDI must have a beans.xml file located in the WEB-INF directory of the application. Given that, let’s create this file and populate it with the required information. Browse to your /src/main/webapp/WEB-INF directory and create a file named beans.xml and add the following code:
<?xml version="1.0"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://jboss.org/schema/cdi/beans_1_0.xsd"/>
We also need to set the our servlet mapping for our REST API calls in the web.xml file. Add the following servlet mapping element to the file located in the /src/main/webapp/WEB-INF directory:
<servlet-mapping>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
<url-pattern>/ws/*</url-pattern>
</servlet-mapping>
Step 3: Creating the DBConnection class
At this point, we have our project setup and our pom.xml file includes the dependency for MongoDB to ensure that the drivers are packaged as part of our application. The next thing we need to do is to create a class that will manage the connection to the database for us. Create a new file named DBConnection.java and place the file in the /src/main/java/com/strongloop/data directory and include the following source code:
Ensure that you replace the connection authorization details with the appropriate information for your installation of MongoDB!
package com.strongloop.data;
import java.net.UnknownHostException;
import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Named;
import com.mongodb.DB;
import com.mongodb.Mongo;
@Named
@ApplicationScoped
public class DBConnection {
private DB mongoDB;
public DBConnection() {
super();
}
@PostConstruct
public void afterCreate() {
String mongoHost = "127.0.0.1"
String mongoPort = "27001"
String mongoUser = "strongloop";
String mongoPassword = "rocks";
String mongoDBName = "restexample";
int port = Integer.decode(mongoPort);
Mongo mongo = null;
try {
mongo = new Mongo(mongoHost, port);
} catch (UnknownHostException e) {
System.out.println("Couldn't connect to MongoDB: " + e.getMessage()
+ " :: " + e.getClass());
}
mongoDB = mongo.getDB(mongoDBName);
if (mongoDB.authenticate(mongoUser, mongoPassword.toCharArray()) == false) {
System.out.println("Failed to authenticate DB ");
}
}
public DB getDB() {
return mongoDB;
}
}
Step 4: Importing data into MongoDB
For our sample application, we are going to load a list of beers that match on the name of “Pabst”. If you are not familiar with beer drinking, the Pabst Brewing Company makes some of the finest American ale available. With signature products such as Pabst Blue Ribbon (PBR) and Colt 45, they have all of your malt drinking beverages basis covered.
pabst-coupon
The first thing you want to do is download a JSON file that has all the data that we want to return. You can grab this at the following URL:
https://dl.dropboxusercontent.com/u/72466829/beers.json
Once you have the data set downloaded, simply load it into your database using the mongoimport command as shown below:
$ mongoimport --jsonArray -d yourDBName -c beers --type json --file /tmp/beers.json -h yourMongoHost --port yourMongoPort -u yourMongoUsername -p yourMongoPassword
You should see the following results:
connected to: 127.0.0.1:27017
Tue Jun 10 20:09:55.436 check 9 24
Tue Jun 10 20:09:55.437 imported 24 objects
Now that we have a database connection class created and the beer information loaded into the MongoDB database, its time to create the model object that will hold our beer information. Create a new file called Beer.java and place it in the /src/main/java/com/strongloop/data directory. Once you have the file created, add the following source code:
package com.strongloop.data;
public class Beer {
private String id;
private String name;
private String description;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
Note: The JSON file provided contains more information that what we will be using so have a poke around and add some additional functionality to expand the learning experience.
Guess what? We are finally ready to create the REST based web service that will allows us to retrieve the beers we loaded in a previous step. To do this, create a new file named BeerWS.java and place it in the /src/main/java/com/strongloop/webservice directory. Once you have the file created, add the following source code:
package com.strongloop.webservice;
import java.util.ArrayList;
import java.util.List;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import com.strongloop.data.DBConnection;
import com.strongloop.data.Beer;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
@RequestScoped
@Path("/beers")
public class BeerWS {
@Inject
private DBConnection dbConnection;
private DBCollection getBeerCollection() {
DB db = dbConnection.getDB();
DBCollection beerCollection = db.getCollection("beers");
return beerCollection;
}
private Beer populateBeerInformation(DBObject dataValue) {
Beer theBeer = new Beer();
theBeer.setName(dataValue.get("name"));
theBeer.setDescription(dataValue.get("name"));
theBeer.setId(dataValue.get("_id").toString());
return theBeer;
}
// get all of the beers
@GET()
@Produces("application/json")
public List<Beer> getAllBeers() {
ArrayList<Beer> allBeersList = new ArrayList<Beer>();
DBCollection beers = this.getBeerCollection();
DBCursor cursor = beers.find();
try {
while (cursor.hasNext()) {
allBeersList.add(this.populateBeerInformation(cursor.next()));
}
} finally {
cursor.close();
}
return allBeersList;
}
}
Whew finally. We now have a REST web service written that will find all of the beers in our database. Deploy your code to your application server and verify it is working by browsing the following URL:
http://yourserverlocation/ws/beers
If everything went as it should, you will see all of the beers listed as shown in the following image:
restexample
If you have been following along with the Java code in this blog post, you have realized that even with great strides being made recently in Java EE land, creating something as simple as a REST service is still very verbose. Don’t get me wrong, I still love working in Java EE but have found that for a lot of tasks, such as creating REST services that return JSON data, Node is the way to go. For the rest of this post, we are going to create the same simple web service using the LoopBack API framework from StrongLoop. As an added bonus, I will walk you through installing Node on OSX.
Step 1: Installing Node
The easiest way to install Node is via one of the available binary packages that is available for most operating systems. Point your browser to the following URL and download the correct one for your operating system:
Once this page loads, you should see the following:
install
If you are using Mac OSX, click on the universal .pkg file. This will save the installation program to your local computer. Once the file has been downloaded, start the installation program by double clicking on the .pkg file that has been downloaded and you will be presented the installation dialog:
wizard
Complete the installation process by using all of the defaults and finally click on the close button to exit the program once the installation has been successful. Pretty easy, huh?
Now that we have Node installed on our local system, we want to install the LoopBack packages that is provided by StrongLoop. LoopBack is an open source API that provides functionality that will make your life easier as you begin to learn how to write and deploy software written in Node.
In order to install LoopBack, we will be using the npm command that is part of the core language. NPM is the official package manager for installing libraries or modules that your applications depend on. Given that this post is written for Java developers, an easy way to think of NPM modules is to relate it to Maven. Using the Maven build system, developers are able to specify dependencies in their pom.xml file. Once the application is scheduled for a build, all of the dependencies are downloaded and the .jar files are included in the project. NPM modules works the same way and uses the package.json file to allow you to specify dependencies for a particular application. You can also install dependencies from the command line to make them available on your local system. Don’t worry if you don’t understand this just yet as we will cover the package.json file in more detail in a later step.
In order to install LoopBack, we can issue a single command that will download and install all of the dependencies we need for the package. Open up your terminal window and issue the following command:
$ npm install -g strongloop
Note: You may have to use sudo depending on your installation
What just happened? We told npm that we want to install the strong-cli package while also providing the -g option. The -g option makes the package available as a global package for anyone of the system to use and is available to all applications. Once you run the above command, NPM will download the package as well as any dependencies that is required. Depending on the speed of your system, this may take a few minutes to complete.
Creating an application using the LoopBack API is very easy and straight-forward. Simply up your terminal window and issue the following command to create a new application called restexample.
$ slc loopback
This prompts for a project directory. Lets pass restexample as the directory name for purposes of this exercise. It then prompts for the application name. We will keep the default restexample.
The slc utility will now create a new LoopBack based project called restexample and configure the project. A new directory will also be created where you ran the command named after the application. Change to the application directory with the cd command:
$ cd restexample
Now that we have our application created, we want to add support for MongoDB as a datasource for LoopBack.
In order to communicate with MongoDB, we need add a datasource to our application. We do that by running:
$ slc loopback:datasource
We get a prompt to enter the data-source name, which can be anything custom. Let’s choose myMongo
[?] Enter the data-source name: myMongo
Now we can attach the backend datasource definition to the real connector supported by StrongLoop. Here we choose the MongoDB connector from the list.
[?] Select the connector for myMongo:
PostgreSQL (supported by StrongLoop)
Oracle (supported by StrongLoop)
Microsoft SQL (supported by StrongLoop)
❯ MongoDB (supported by StrongLoop)
SOAP webservices (supported by StrongLoop)
REST services (supported by StrongLoop)
Neo4j (provided by community)
(Move up and down to reveal more choices)
In order to communicate with MongoDB, we need point at the actual MongoDB instance. LoopBack defines all datasource configuration in the datasource.json file that is located in your application root/server directory. Open this file and add a datasource for MongoDB as shown in the following code:
{
"db": {
"name": "db",
"connector": "memory"
},
"myMongo": {
"name": "myMongo",
"connector": "mongodb"
"url": "mongodb://localhost:27017/restexample"
}
}
Note: Be sure to provide the correct connection URL for your MongoDB database. For this example, I have a database created called restexample that I want to use for my datasource.
Just as we did during the Java section of this post, we need to load the data set into our MongoDB database. If you have already completed this step as part of this blog post and you intend to use the same database, you can skip ahead to Step 7.
The first thing you want to do is download a JSON file that has all the data that we want to return. You can grab this at the following URL:
https://dl.dropboxusercontent.com/u/72466829/beers.json
Once you have the data set downloaded, simply load it into your database using the mongoimport command as shown below:
$ mongoimport --jsonArray -d yourDBName -c beers --type json --file /tmp/beers.json -h yourMongoHost --port yourMongoPort -u yourMongoUsername -p yourMongoPassword
You should see the following results:
connected to: 127.6.189.2:27017
Tue Jun 10 20:09:55.436 check 9 24
Tue Jun 10 20:09:55.437 imported 24 objects
Step 7: Creating our Beer model
A model can be thought of in the same terms as you think about models in Java land. It is a representation of an Object which in this case is beer. LoopBack provides a convenient way to create model objects by using the command line. Open up your terminal window, go to the project folder and issue the following command:
$ slc loopback:model
This will begin an interactive session where you can define your model. The first thing that will be asked is the model name. Let’s call that “beer”. It will prompt for the datasource this model should be attached to and we should select the myMongo datasource we just created.
[?] Enter the model name: beer
[?] Select the data-source to attach beer to:
db (memory)
❯ myMongo (mongodb)
We then get prompted if this API should be exposed over REST. Of course we want to do that.
[?] Expose beer via the REST API? Yes
Finally a web plural name for your model. Since our model is called beer, the plural is beers (which is the default). To accept this default, simply hit the enter key.
[?] Custom plural form (used to build REST URL):
The next thing that you will be asked is to define the properties of your model. For this sample application, we are interested in the name and description of the beer.
Enter an empty property name when done.
[?] Property name: name
Once you hit enter, you will be asked to provide the data type for each property specified. The first item will be name and we want to select that it is of type string. Select string and press the enter key.
[?] Property type: (Use arrow keys)
❯ string
number
boolean
object
array
date
buffer
geopoint
(other)
You can then create similarly the description property and will then be asked to specify the type. This is also a string so select that option and press enter.
Let's add another beer property. Enter an empty property name when done. [?] Property name: description invoke loopback:property [?] Property type: string [?] Required? Yes
Congratulations! you have just created your first model object using LoopBack in conjunction with Node. To see what was actually created under the covers, open up the beer.json file that is located in the root/common/models of your application directory. Scroll to the very bottom of the file and you will see the following model:
{
"name": "beer",
"base": "PersistedModel",
"properties": {
"name": {
"type": "string",
"required": true
},
"description": {
"type": "string",
"required": true
}
},
"validations": [],
"relations": {},
"acls": [],
"methods": []
}
As you can see, we have a model created and the name as well as the description properties are assigned to the model.
In the /server/model-config.js you will notice we also have some additional fields including public and datasource. The public field specifies that we want to expose this model to the world via a REST web service. The datasource field specifies the datasource that this model will use for CRUD operations.
"beer": {
"dataSource": "myMongo",
"public": true
}
Step 8: Bask in the joy of viewing beers
Congratulations! You have just created your first Node.js application that includes a REST web service for retrieving information about beer! The last thing we need to do is deploy the application. Fortunately, this is a very easy task and can be performed with the following command that should be executed from your application’s root directory:
$ slc run
Once the application is running, verify that is working by going to the following URL with your web browser:
`` http://0.0.0.0:3000/api/beers
LoopBack also includes an explorer application that will allow you to view all of the services available for your application, including the Beer model and REST service that we created. To use this explorer, point your browser to the following URL:
``
http://0.0.0.0:3000/explorer
Once the page has loaded, you will be presented with the following screen where I have highlighted the /beers endpoint that we created as part of this blog post:
explorer1
You can click on the /beers endpoint to expand the available API calls that can be made and even test a few out as shown in the following image:
explorer2
Conclusion In this blog post I showed you how to create a REST based web service using Java EE. This service returned a list of beers from the fantastic Pabst Brewing Company. After we created the Java EE application, we then created the same application using LoopBack and Node. With very little code, we were able to create a REST web service that returns the name and description of our beers. On top of that, the LoopBack API also provides default actions for the entire CRUD process.