package com.ibm.personafusion.db; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import org.ektorp.CouchDbConnector; import org.ektorp.CouchDbInstance; import org.ektorp.http.HttpClient; import org.ektorp.http.StdHttpClient; import org.ektorp.impl.StdCouchDbConnector; import org.ektorp.impl.StdCouchDbInstance; import com.ibm.json.java.JSONArray; import com.ibm.json.java.JSONObject; import com.ibm.personafusion.Config; import com.ibm.personafusion.Constants; import com.ibm.personafusion.controller.JsonUtils; import com.ibm.personafusion.model.Person; import com.ibm.personafusion.model.Trait; /** A class for communicating with the Cloudant datastore. * See main() for example usage. * * @author Sean Welleck**/ public class CloudantClient { private HttpClient httpClient; private CouchDbConnector dbc; private int port; private String name; private String host; private String username; private String password; private JSONArray cloudant; private JSONObject cloudantInstance; private JSONObject cloudantCredentials; public CloudantClient() { this.httpClient = null; try { String VCAP_SERVICES = System.getenv("VCAP_SERVICES"); JSONObject vcap; vcap = (JSONObject) JSONObject.parse(VCAP_SERVICES); cloudant = (JSONArray) vcap.get("cloudantNoSQLDB"); cloudantInstance = (JSONObject) cloudant.get(0); cloudantCredentials = (JSONObject) cloudantInstance.get("credentials"); } catch (IOException e) { e.printStackTrace(); } this.port = Config.CLOUDANT_PORT; this.host = (String) cloudantCredentials.get("host"); this.username = (String) cloudantCredentials.get("username"); this.password = (String) cloudantCredentials.get("password"); this.name = Config.CLOUDANT_NAME; this.dbc = this.createDBConnector(); } /** Put a Person into Cloudant using person.name as the unique id. * Stored as : * { * id: person.name, * type: Person.class, * group: person.group, * json: toJSON(person) * } */ public void putPerson(Person p) { HashMap<String, Object> data = new HashMap<String, Object>(); String name = p.name.toUpperCase(); String group = p.group; data.put(Constants.ID_KEY, name); data.put(Constants.TYPE_KEY, Person.class.getName()); data.put(Constants.GROUP_KEY, group); System.out.println(data.get(Constants.TYPE_KEY)); data.put(Constants.JSON_KEY, JsonUtils.getJson(p)); this.putItem(data); } /** Get a Person from Cloudant using name as the unique id. **/ public Person getPerson(String name) { name = name.toUpperCase(); @SuppressWarnings("unchecked") HashMap<String, Object> obj = this.dbc.get(HashMap.class, name); Person p = JsonUtils.getPersonFromJson((String)obj.get(Constants.JSON_KEY)); return p; } /** Get all Person objects from Cloudant. **/ public List<Person> getAllPeople() { List<Person> people = new ArrayList<Person>(); List<String> docIds = dbc.getAllDocIds(); for(String docId : docIds) { @SuppressWarnings("unchecked") HashMap<String, Object> obj = this.dbc.get(HashMap.class, docId); if (obj.get(Constants.TYPE_KEY) != null && obj.get(Constants.TYPE_KEY).equals(Person.class.getName())) { String json = (String)obj.get(Constants.JSON_KEY); Person p = JsonUtils.getPersonFromJson(json); people.add(p); } } System.out.println( String.format("Retrieved %d Person entries.", people.size())); return people; } /** Get all Person objects in the specified group from Cloudant. **/ public List<Person> getAllPeopleInGroup(String groupName) { List<Person> people = new ArrayList<Person>(); List<String> docIds = dbc.getAllDocIds(); for(String docId : docIds) { @SuppressWarnings("unchecked") HashMap<String, Object> obj = this.dbc.get(HashMap.class, docId); if (obj.get(Constants.TYPE_KEY) != null && obj.get(Constants.TYPE_KEY).equals(Person.class.getName()) && obj.get(Constants.GROUP_KEY) != null && obj.get(Constants.GROUP_KEY).equals(groupName)) { String json = (String)obj.get(Constants.JSON_KEY); Person p = JsonUtils.getPersonFromJson(json); people.add(p); } } System.out.println(String.format( "Retrieved %d Person entries for group %s.", people.size(), groupName)); return people; } /** Get all Person objects in the specified group from Cloudant. **/ public List<Person> getAllPeopleNotInGroup(String groupName) { List<Person> people = new ArrayList<Person>(); List<String> docIds = dbc.getAllDocIds(); for(String docId : docIds) { @SuppressWarnings("unchecked") HashMap<String, Object> obj = this.dbc.get(HashMap.class, docId); if (obj.get(Constants.TYPE_KEY) != null && obj.get(Constants.TYPE_KEY).equals(Person.class.getName()) && obj.get(Constants.GROUP_KEY) != null && !obj.get(Constants.GROUP_KEY).equals(groupName)) { String json = (String)obj.get(Constants.JSON_KEY); Person p = JsonUtils.getPersonFromJson(json); people.add(p); } } System.out.println(String.format( "Retrieved %d Person entries that are not in group %s.", people.size(), groupName)); return people; } /** Delete all documents from the Cloudant datastore. Use with caution. **/ public void deleteAll() { List<String> docIds = this.dbc.getAllDocIds(); int startSize = docIds.size(); for(String docId : docIds) { @SuppressWarnings("unchecked") HashMap<String, Object> obj = this.dbc.get(HashMap.class, docId); this.dbc.delete(obj); } docIds = this.dbc.getAllDocIds(); int endSize = docIds.size(); System.out.println( String.format( "Deleted all entries. Starting size: %d. Current size: %d.", startSize, endSize)); } public void deletePerson(Person p) { String name = p.name.toUpperCase(); List<String> docIds = this.dbc.getAllDocIds(); int startSize = docIds.size(); @SuppressWarnings("unchecked") HashMap<String, Object> obj = this.dbc.get(HashMap.class, name); this.dbc.delete(obj); docIds = this.dbc.getAllDocIds(); int endSize = docIds.size(); System.out.println( String.format( "Deleted entry %s. Starting size: %d. Current size: %d.", name, startSize, endSize)); } /** Put a generic item modeled as Key-Value pairs into Cloudant. **/ private void putItem(HashMap<String, Object> data) { if (data == null) { System.err.println("data cannot be null in putItem()"); return; } String id = (String)data.get(Constants.ID_KEY); if (id == null) { System.err.println("data must have an _id field."); return; } if (this.dbc.contains(id)) { System.err.println("Didn't putItem. _id=" + id + " already exists."); return; } this.dbc.create(data); System.out.println("Put _id=" + id + " into the datastore."); } private CouchDbConnector createDBConnector() { CouchDbInstance dbInstance = null; System.out.println("Creating CouchDB instance..."); System.out.println(this.username); this.httpClient = new StdHttpClient.Builder() .host(this.host) .port(this.port) .username(this.username) .password(this.password) .enableSSL(true) .relaxedSSLSettings(true) .build(); dbInstance = new StdCouchDbInstance(this.httpClient); CouchDbConnector dbc = new StdCouchDbConnector(this.name, dbInstance); dbc.createDatabaseIfNotExists(); if (dbc.getAllDocIds().size() == 0) { dbc.replicateFrom("https://jsloyer.cloudant.com/talent-manager"); while (true) { if (dbc.getAllDocIds().size() == 117) { break; } else { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } } } return dbc; } private void closeDBConnector() { if (httpClient != null) { httpClient.shutdown(); } } /** Example usage. **/ public static void main(String[] args) throws Exception { CloudantClient cc = new CloudantClient(); Person p = new Person("Alan Xia", null, null); p.group = "group1"; cc.putPerson(p); List<Trait> traits = new ArrayList<Trait>(); traits.add(new Trait("programming", .9)); traits.add(new Trait("being awesome", .95)); Person p2 = new Person("Dev God", traits, null); p2.group = "group2"; cc.putPerson(p2); Person testPerson = cc.getPerson("Dev God"); System.out.println(testPerson.name); System.out.println(testPerson.traits); List<Person> people = cc.getAllPeople(); System.out.println("There are " + people.size() + " people."); List<Person> g1ppl = cc.getAllPeopleInGroup("group1"); System.out.println("There are " + g1ppl.size() + " people in group1."); List<Person> notg1ppl = cc.getAllPeopleNotInGroup("group1"); System.out.println(notg1ppl.get(0).name + " is not in group1."); cc.deletePerson(p); cc.deletePerson(p2); cc.closeDBConnector(); } }