Community

Java and Cloudant NoSQL DB on Bluemix

Share this post:

Cloudant is a stellar NoSQL DBaaS (Database as a Service) that allows developers to not worry about their database infrastructure. If you’ve never used Cloudant or a cloud database offering before, this is where you should get started. Within the large catalog of services we provide with Bluemix, Cloudant shines as one of the simplest databases to create and use. In this sample, we will quickly create a web application that talks to Cloudant using the “ektorp” client jar for Java and then push it to Bluemix. We will create this web application using a Maven project in Eclipse. I’ve chosen Maven because it is the easiest way to retrieve the dependencies we need — the “ektorp” client jars.

When pushing your application to ‘Liberty for Bluemix’ with the Cloudant service bound to it, we make the service easier to consume with a process we call “auto-configuration”. Basically, we add configuration elements to the “server.xml” of the Liberty server running your application. This aspect of Bluemix is key for making the application development process as stream-lined as possible. You can read more about what exactly the auto-config for Cloudant does here: Cloudant Docs on Bluemix

Requirements:

Steps:

  1. Open Eclipse and create a new Maven projectNew Maven Project
    • File > New > (Other) > Maven Project
    • Check “Create a simple project (skip archetype selection)” > Next
    • Set the following values
      • Group ID: com.blog
      • Artifact ID: sample
      • Version: 1
      • Packaging: war
    • Leave everything else as-is and Click Finish
  2. Ensure that the projected is faceted properlyFacets
    • Right Click your project > Properties > Project Facets
    • Check Dynamic Web Module
    • Change Java version to 1.6 or 1.7 (you may need to change the JRE of your project to match this)
    • Click Finish
  3. Copy dependencies into pom.xml in the <project> stanza

    pom.xml:

    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.ektorp</groupId>
            <artifactId>org.ektorp</artifactId>
            <version>1.4.1</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    

    Note: The “provided” tag means that the container/runtime (in our case, Liberty) will provide these dependencies for your application. This means that Eclipse does not package them in your application’s WEB-INF directory. When pushing your WAR to Bluemix, you should not include the ektorp dependencies in your WEB-INF/lib directory or you will run into classloading issues.

    Save the file

  4. Generate the web.xml which will be used for servlet-mappingGeneration
    • Right click project > Java EE Tools > Generate Deployment Descriptor Stub (may be grayed out if the web.xml already exists)
  5. Create a servlet
    • Right click Project > New > (Other) > Web > Servlet
    • Ensure source folder is sample\src\main\java
    • Java package: com.out
    • Class name: SimpleServlet
    • Click Finish
  6. Ensure servlet mapping is in the web.xml (src/main/webapp/WEB-INF/web.xml)
      <servlet>
        <display-name>SimpleServlet</display-name>
        <servlet-name>SimpleServlet</servlet-name>
        <servlet-class>com.out.SimpleServlet</servlet-class>
      </servlet>
      <servlet-mapping>
        <servlet-name>SimpleServlet</servlet-name>
        <url-pattern>/SimpleServlet</url-pattern>
      </servlet-mapping>
    
  7. Choose one of the two options to have your servlet create a database and add a document.
    Option 1 (Resource Injection):
    This method might not work when using wink servlets
    Add to your servlet (src/main/java/com/out/SimpleServlet.java — replace doGet method)
    import javax.annotation.Resource;
    
    import org.ektorp.CouchDbConnector;
    import org.ektorp.CouchDbInstance;
    
    import java.util.HashMap;
    import java.util.Map;
    import java.util.UUID;
    

    and

        @Resource(name = "couchdb/cloudant-sample")
        protected CouchDbInstance _db;
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            String dbname = "my_database";
            try {
                //creates a database with the specified name
                CouchDbConnector dbc = _db.createConnector(dbname, true);
                response.getWriter().println("Created database: " + dbname);
                //create a simple doc to place into your new database
                Map<String, Object> doc = new  HashMap<String, Object>();
                doc.put("_id",  UUID.randomUUID().toString());
                doc.put("season", "summer");
                doc.put("climate", "arid");
                dbc.create(doc);
                response.getWriter().println("Added a simple doc!");
            } catch (Exception e) {
                response.getWriter().println(e.getMessage());
            }
        }
    

    Note: If you still have import issues, ensure your pom.xml is configured correctly and that your project’s Java facet is on 1.6 or 1.7

    Option 2 (JNDI lookup):
    Add to your servlet (src/main/java/com/out/SimpleServlet.java — replace doGet method)

    import javax.annotation.Resource;
    
    import org.ektorp.CouchDbConnector;
    import org.ektorp.CouchDbInstance;
    
    import java.util.HashMap;
    import java.util.Map;
    import java.util.UUID;
    
    import javax.naming.InitialContext;
    

    and

        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            String dbname = "my_database";
            CouchDbInstance _db = null;
            try {
                _db = (CouchDbInstance) new InitialContext().lookup("java:comp/env/couchdb/cloudant-sample");
                //creates a database with the specified name
                CouchDbConnector dbc = _db.createConnector(dbname, true);
                response.getWriter().println("Created database: " + dbname);
                //create a simple doc to place into your new database
                Map<String, Object> doc = new  HashMap<String, Object>();
                doc.put("_id",  UUID.randomUUID().toString());
                doc.put("season", "summer");
                doc.put("climate", "arid");
                dbc.create(doc);
                response.getWriter().println("Added a simple doc!");
            } catch (Exception e) {
                response.getWriter().println(e.getMessage());
            }
        }
    

    and add to your web.xml (src/main/java/webapp/web.xml)

    <resource-env-ref>
        <resource-env-ref-name>couchdb/cloudant-sample</resource-env-ref-name>
        <resource-env-ref-type>org.ektorp.CouchDbInstance</resource-env-ref-type>
    </resource-env-ref>
    

    Note: If you still have import issues, ensure your pom.xml is configured correctly and that your project’s Java facet is on 1.6 or 1.7

  8. Right click project > Export > Web > WAR file
  9. Push your WAR file to Bluemix (First time? Learn here).
    The following command creates your application but doesn’t start it (we don’t want to start it until we bind our Cloudant service)
    cf push &lt;some_unique_app_name&gt; -m 512M -p &lt;path_to_your_war_file&gt; --no-start
  10. Create and bind a Cloudant service using CLI or ACE. The service must be named “cloudant-sample“.
    Note: The name of the service determines the name of the db connector resource in the namespace. Since we named it cloudant-sample, the resource will be under the namespace “couchdb/cloudant-sample”. All Cloudant db connector resources have the prefix “couchdb/”. The @Resource annotation/JNDI-lookup we used in the servlet complies with this.
    Cloudant Service
    Cloudant
  11. Repush. You must repush for the environment variable changes to take effect.
    Note: If you are using ACE, there may be a pop-up asking if you want to restart your application. This is insufficient — you still need to push your application using CF.

    cf push &lt;some_unique_app_name&gt; -m 512M -p &lt;path_to_your_war_file&gt;
  12. Access your application and append “/SimpleServlet” to the end of the URL. You should see a message telling you that the database has been created. For example, if my application is at myCoolApp.mybluemix.net, I would need to hit myCoolApp.mybluemix.net/SimpleServlet.
  13. Go to ACE and click your service — “cloudant-sample”. Then, launch your Cloudant dashboard using the “Launch” button. You’ll see your database “my_database” in the dashboard!
    Cloudant-sample

Add Comment
20 Comments

Leave a Reply

Your email address will not be published.Required fields are marked *


Andrew

Great post! very easy steps and simple to follow.

Reply

Rajesh K Jeyapaul

Sai , I need sample code to read a file stored in cloudant no sql database. My requirement is to read from the file and update my local variables input1,input2,input3 as defined in the code below:
.
public class propread {
static String input1,input2,input3;
/**
* @param args
*/
public static void main(String[] args) {

InputStream input = null;
String dbname=”cloudtestj24″;

@Resource(name = “cloudant/Cloudant NoSQL DB-jj”)
private CouchDbInstance db;

try {

CouchDbInstance db = (CouchDbInstance) new InitialContext().lookup(“java:comp/env/cloudant/Cloudant NoSQL DB-jj”);
…???

Reply

    Sai Vennam

    Sure! I’ve found a couple of issues in your code, though.
    1) You can use either the @Resource annotation to create your CouchDbInstance OR the InitialContext().lookup. You don’t have to do both.
    2) Avoid using spaces in your JNDI name. I’m not entirely sure if that’ll cause any issues, but it’s better to be safe 🙂
    3) You need to create your CouchDbConnector. Here’s an example how:
    //’db’ is your CouchDbInstance you created using JNDI lookup or @Resource
    CouchDbConnector dbc = db.createConnector(dbname, true);

    Reply

      Sai Vennam

      As for your original question, there’s many different ways to do it! Ektorp documentation will help: http://ektorp.org/reference_documentation.html

      You can also Google more about some of the ways I’ll outline here:
      Note: In the following examples, ‘dbc’ is your CouchDbConnector
      1) Manually:
      //You have to know your document ID (the _id field) for this
      InputStream s = dbc.getAsStream(document_id);
      ObjectMapper mapper = new ObjectMapper();
      Map jsonMap = mapper.readValue(s, Map.class);
      //You can also use getAttachment to get attachment files
      dbc.getAttachment(document_id, attachmentId);

      Reply

        Sai Vennam

        2) You can use view queries to get a list of documents mapped to rows. Then you can use these rows to retrieve documents as `JsonNode`s. Here’s a simple example:
        //Creates a view of all documents
        ViewQuery q = new ViewQuery().allDocs().includeDocs(true);
        ViewResult vr = dbc.queryView(q);
        List rows = vr.getRows();
        //Gets the first row as a JsonNode
        rows.get(0).getDocAsNode();

        Reply

          Sai Vennam

          3) Implement a getter/setter class as a CouchDbDocument. For example, the “Sofa” class here: http://ektorp.org/reference_documentation.html#d100e539
          Then, you can get a document from Cloudant as that class:
          String id = … Sofa
          sofa = dbc.get(Sofa.class, id);
          String color = Sofa.getColor();

          Let me know if you have any questions!


          Sai Vennam

          Oops, that should be:
          String id = …
          Sofa sofa = dbc.get(Sofa.class, id);
          String color = Sofa.getColor();


Eyal

Hi,

I tried that but the @Resource CouchDbInstance is not being injected, even querying the InitialContext I get javax.naming.NameNotFoundException: java:comp/env/couchdb/Cloudant-NoSQL-DB-ns

Seems that CDI/JNDI is not working at all… even @inject seems not to work
My setup: web.xml with org.apache.wink.server.internal.servlet.RestServlet with
init-param “applicationConfigLocation” containg my JAX-RS resources

What am I missing?
Thank

Reply

    Sai Vennam

    I’ve updated the guide. You’ll notice that there are now two options for step 7. Try JNDI lookup rather than resource injection — it should work for you.

    Reply

Jason

Have you run the app in your local liberty profile? I got error message: java.lang.NoClassDefFoundError: org/ektorp/CouchDbInstance

Reply

    Sai Vennam

    Hi Jason,
    With this blog, I wanted to showcase the fact that Bluemix sets up a lot of the config which can be a pain to do a local development environment. This allows developers to focus on developing via Dev Ops (Web IDE).
    If you wanted to set-up a CouchDB/Cloudant connection locally, you can follow the documentation here:
    https://www-01.ibm.com/support/knowledgecenter/was_beta_liberty/com.ibm.websphere.wlp.nd.multiplatform.doc/ae/twlp_couchdb_create.html

    Reply

      Bede

      Hi Sai,

      I’ve attempted with no success to follow the documentation on setting up a local jndi resource to connect to a local couchdb instance (https://www-01.ibm.com/support/knowledgecenter/was_beta_liberty/com.ibm.websphere.wlp.nd.multiplatform.doc/ae/twlp_couchdb_create.html).

      The error I get is ‘Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘myMsdNosqlDb’:
      Unsatisfied dependency expressed through constructor argument with index 1 of type [org.ektorp.CouchDbInstance]:
      Could not convert constructor argument value of type [org.ektorp.impl.StdCouchDbInstance] to required type [org.ektorp.CouchDbInstance]:
      Failed to convert value of type ‘org.ektorp.impl.StdCouchDbInstance’ to required type ‘org.ektorp.CouchDbInstance’; nested exception is java.lang.IllegalStateException:
      Cannot convert value of type [org.ektorp.impl.StdCouchDbInstance] to required type [org.ektorp.CouchDbInstance]: no matching editors or conversion strategy found’

      What is the best venue to ask for help on this issue?

      Regards

      Reply

Jason

If you can show us local deployment on Liberty Profile 8.5.5 instead of Bluemix, that will be very great since most developments are done in local.

Reply

ruchi

Hi,

I am trying to fork the code into my bluemix.
I am a ETL developer.
Could you please help me where i need to change the directory path.I am getting error: /jason/lib not found…

Reply

PrakashDasariraju

Hi Sai,
I am not using a maven project, but the normal dynamic web project and using cloudant-client-1.2.2 api to connect to cloudant DB to store attachments/images in there. Is there any way to configure a jndi lookup / @resource into my application. And I am running my application on liberty profile server.

Reply

MangeshPatankar

Sai,

I am getting error org.ektorp.impl.StdCouchDbInstance incompatible with org.ektorp.CouchDbInstance , while accessing servlet.
using ektorp 1.4.1 only

Reply

Rajesh Jena

Hey Sai,
I want to create a search index in my cloudant db using java.
But when am trying to use java cloudant api am not getting the desired result.
But, when am creating the same in cloudant db itself and then when am trying to query the search index using java then it’s successful.
So, please if you can help me in creating the search index using java.

Reply

Guglielmo Bittarelli

Very interesting, I used Eclipse to deploy ..very more comfortable. thank you

Reply
More How-tos Stories

Utilizing Multi-Container Functionality with IBM Cloud Developer Tools CLI

The latest update to the IBM Cloud Developer Tools CLI, version 1.1.0, provides support for applications that use multiple containers which are configured using Docker Compose yaml files. These files contain necessary information about the containers you wish to run. With Docker installed, you already have the requisite dependency to run multiple containers locally.

Continue reading

Integrate and Analyze Diagnostic Logs with IBM Cloud Log Analysis

Analyzing diagnostic logs, monitoring application health and keeping track of security-related events are at the foundation of successfully running apps and services. IBM Cloud offers services for that purpose. Today, I am going to show you how to use IBM Cloud Log Analysis to integrate, search and analyze as well as visualize diagnostic logs in the IBM Cloud.

Continue reading

Obey your commands: Home automation using Watson and PubNub

Integration of voice control in smart devices is buzzing, and adoption continues to grow. Voice control provides a more natural way of interacting with connected apps and devices ranging from news feeds, traffic information to acting as personal assistants in the home. These intelligent devices respond to commands spoken in our own voice and act immediately.

Continue reading