RYA-84 Add Mongo Support to Admin Table

Implemented admin table interfaces with MongoDB.

Added Test coverage for the Mongo object to RyaDetails
adapter and integration tests for the repo.


Project: http://git-wip-us.apache.org/repos/asf/incubator-rya/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rya/commit/ec598be4
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rya/tree/ec598be4
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rya/diff/ec598be4

Branch: refs/heads/master
Commit: ec598be4e457ea5782920480dc6dc035947bba04
Parents: 9bdbbf5
Author: isper3at <[email protected]>
Authored: Wed Jun 8 02:37:20 2016 -0400
Committer: Aaron Mihalik <[email protected]>
Committed: Tue Aug 23 10:41:37 2016 -0400

----------------------------------------------------------------------
 .../java/mvm/rya/api/instance/RyaDetails.java   |  25 +-
 .../mongodb/instance/MongoDetailsAdapter.java   | 175 ++++++++++
 .../MongoRyaInstanceDetailsRepository.java      | 125 +++++++
 .../instance/MongoDetailsAdapterTest.java       | 230 +++++++++++++
 .../instance/MongoRyaDetailsRepositoryIT.java   | 325 +++++++++++++++++++
 5 files changed, 871 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/ec598be4/common/rya.api/src/main/java/mvm/rya/api/instance/RyaDetails.java
----------------------------------------------------------------------
diff --git a/common/rya.api/src/main/java/mvm/rya/api/instance/RyaDetails.java 
b/common/rya.api/src/main/java/mvm/rya/api/instance/RyaDetails.java
index 895eb36..9130144 100644
--- a/common/rya.api/src/main/java/mvm/rya/api/instance/RyaDetails.java
+++ b/common/rya.api/src/main/java/mvm/rya/api/instance/RyaDetails.java
@@ -220,15 +220,15 @@ public class RyaDetails implements Serializable {
         public Builder(final RyaDetails details) {
             requireNonNull(details);
 
-            this.instanceName = details.instanceName;
-            this.version = details.version;
-            this.entityCentricDetails = details.entityCentricDetails;
-            this.geoDetails = details.geoDetails;
-            this.pcjDetails = details.pcjDetails;
-            this.temporalDetails = details.temporalDetails;
-            this.freeTextDetails = details.freeTextDetails;
-            this.prospectorDetails = details.prospectorDetails;
-            this.joinSelectivityDetails = details.joinSelectivityDetails;
+            instanceName = details.instanceName;
+            version = details.version;
+            entityCentricDetails = details.entityCentricDetails;
+            geoDetails = details.geoDetails;
+            pcjDetails = details.pcjDetails;
+            temporalDetails = details.temporalDetails;
+            freeTextDetails = details.freeTextDetails;
+            prospectorDetails = details.prospectorDetails;
+            joinSelectivityDetails = details.joinSelectivityDetails;
         }
 
         /**
@@ -658,6 +658,13 @@ public class RyaDetails implements Serializable {
                 this.updateAppName = requireNonNull(updateAppName);
             }
 
+            /**
+             * @return The name of the Fluo application.
+             */
+            public String getUpdateAppName() {
+                return updateAppName;
+            }
+
             @Override
             public int hashCode() {
                 return Objects.hash(updateAppName);

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/ec598be4/dao/mongodb.rya/src/main/java/mvm/rya/mongodb/instance/MongoDetailsAdapter.java
----------------------------------------------------------------------
diff --git 
a/dao/mongodb.rya/src/main/java/mvm/rya/mongodb/instance/MongoDetailsAdapter.java
 
b/dao/mongodb.rya/src/main/java/mvm/rya/mongodb/instance/MongoDetailsAdapter.java
new file mode 100644
index 0000000..ffc4ab1
--- /dev/null
+++ 
b/dao/mongodb.rya/src/main/java/mvm/rya/mongodb/instance/MongoDetailsAdapter.java
@@ -0,0 +1,175 @@
+package mvm.rya.mongodb.instance;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.mongodb.BasicDBList;
+import com.mongodb.BasicDBObject;
+import com.mongodb.BasicDBObjectBuilder;
+import com.mongodb.DBObject;
+
+import mvm.rya.api.instance.RyaDetails;
+import mvm.rya.api.instance.RyaDetails.EntityCentricIndexDetails;
+import mvm.rya.api.instance.RyaDetails.FreeTextIndexDetails;
+import mvm.rya.api.instance.RyaDetails.GeoIndexDetails;
+import mvm.rya.api.instance.RyaDetails.JoinSelectivityDetails;
+import mvm.rya.api.instance.RyaDetails.PCJIndexDetails;
+import mvm.rya.api.instance.RyaDetails.PCJIndexDetails.FluoDetails;
+import mvm.rya.api.instance.RyaDetails.PCJIndexDetails.PCJDetails;
+import 
mvm.rya.api.instance.RyaDetails.PCJIndexDetails.PCJDetails.PCJUpdateStrategy;
+import mvm.rya.api.instance.RyaDetails.ProspectorDetails;
+import mvm.rya.api.instance.RyaDetails.TemporalIndexDetails;
+
+/**
+ * Serializes configuration details for use in Mongo.
+ * The {@link DBObject} will look like:
+ * <pre>
+ * {@code
+ * {
+ *   "instanceName": &lt;string&gt;,
+ *   "version": &lt;string&gt;?,
+ *   "entityCentricDetails": &lt;boolean&gt;,
+ *   "geoDetails": &lt;boolean&gt;,
+ *   "pcjDetails": {
+ *       "enabled": &lt;boolean&gt;,
+ *       "fluoName": &lt;string&gt;,
+ *       "pcjs": [{
+ *           "id": &lt;string&gt;,
+ *           "updateStrategy": &lt;string&gt;,
+ *           "lastUpdate": &lt;date&gt;
+ *         },...,{}
+ *       ]
+ *   },
+ *   "temporalDetails": &lt;boolean&gt;,
+ *   "freeTextDetails": &lt;boolean&gt;,
+ *   "prospectorDetails": &lt;date&gt;,
+ *   "joinSelectivityDetails": &lt;date&gt;
+ * }
+ * </pre>
+ */
+@ParametersAreNonnullByDefault
+public class MongoDetailsAdapter {
+    public static final String INSTANCE_KEY = "instanceName";
+    public static final String VERSION_KEY = "version";
+
+    public static final String ENTITY_DETAILS_KEY = "entityCentricDetails";
+    public static final String GEO_DETAILS_KEY = "geoDetails";
+    public static final String PCJ_DETAILS_KEY = "pcjDetails";
+    public static final String PCJ_ENABLED_KEY = "enabled";
+    public static final String PCJ_FLUO_KEY = "fluoName";
+    public static final String PCJ_PCJS_KEY = "pcjs";
+    public static final String PCJ_ID_KEY = "id";
+    public static final String PCJ_UPDATE_STRAT_KEY = "updateStrategy";
+    public static final String PCJ_LAST_UPDATE_KEY = "lastUpdate";
+    public static final String TEMPORAL_DETAILS_KEY = "temporalDetails";
+    public static final String FREETEXT_DETAILS_KEY = "freeTextDetails";
+
+    public static final String PROSPECTOR_DETAILS_KEY = "prospectorDetails";
+    public static final String JOIN_SELECTIVITY_DETAILS_KEY = 
"joinSelectivitiyDetails";
+
+    /**
+     * Serializes {@link RyaDetails} to mongo {@link DBObject}.
+     * @param details - The details to be serialized.
+     * @return The mongo {@link DBObject}.
+     */
+    public static BasicDBObject toDBObject(final RyaDetails details) {
+        Preconditions.checkNotNull(details);
+        final BasicDBObjectBuilder builder = BasicDBObjectBuilder.start()
+            .add(INSTANCE_KEY, details.getRyaInstanceName())
+            .add(VERSION_KEY, details.getRyaVersion())
+            .add(ENTITY_DETAILS_KEY, 
details.getEntityCentricIndexDetails().isEnabled())
+            .add(GEO_DETAILS_KEY, details.getGeoIndexDetails().isEnabled())
+            .add(PCJ_DETAILS_KEY, getPCJDetailsDBObject(details))
+            .add(TEMPORAL_DETAILS_KEY, 
details.getTemporalIndexDetails().isEnabled())
+            .add(FREETEXT_DETAILS_KEY, 
details.getFreeTextIndexDetails().isEnabled());
+        if(details.getProspectorDetails().getLastUpdated().isPresent()) {
+            builder.add(PROSPECTOR_DETAILS_KEY, 
details.getProspectorDetails().getLastUpdated().get());
+        }
+        if(details.getJoinSelectivityDetails().getLastUpdated().isPresent()) {
+            builder.add(JOIN_SELECTIVITY_DETAILS_KEY, 
details.getJoinSelectivityDetails().getLastUpdated().get());
+        }
+        return (BasicDBObject) builder.get();
+    }
+
+    private static DBObject getPCJDetailsDBObject(final RyaDetails details) {
+        final PCJIndexDetails pcjDetails = details.getPCJIndexDetails();
+        final BasicDBObjectBuilder pcjBuilder = BasicDBObjectBuilder.start()
+            .add(PCJ_ENABLED_KEY, pcjDetails.isEnabled());
+        if(pcjDetails.getFluoDetails().isPresent()) {
+            pcjBuilder.add(PCJ_FLUO_KEY, 
pcjDetails.getFluoDetails().get().getUpdateAppName());
+        }
+        final List<DBObject> pcjDetailList = new ArrayList<>();
+        for(final PCJDetails pcjDetail : pcjDetails.getPCJDetails()) {
+            final BasicDBObjectBuilder indBuilbder = 
BasicDBObjectBuilder.start()
+                .add(PCJ_ID_KEY, pcjDetail.getId())
+                .add(PCJ_UPDATE_STRAT_KEY, 
pcjDetail.getUpdateStrategy().name());
+            if(pcjDetail.getLastUpdateTime().isPresent()) {
+                indBuilbder.add(PCJ_LAST_UPDATE_KEY, 
pcjDetail.getLastUpdateTime().get());
+            }
+            pcjDetailList.add(indBuilbder.get());
+        }
+        pcjBuilder.add(PCJ_PCJS_KEY, pcjDetailList.toArray());
+        return pcjBuilder.get();
+    }
+
+    public static RyaDetails toRyaDetails(final DBObject mongoObj) throws 
MalformedRyaDetailsException {
+        final BasicDBObject basicObj = (BasicDBObject) mongoObj;
+        try {
+        return RyaDetails.builder()
+            .setRyaInstanceName(basicObj.getString(INSTANCE_KEY))
+            .setRyaVersion(basicObj.getString(VERSION_KEY))
+            .setEntityCentricIndexDetails(new 
EntityCentricIndexDetails(basicObj.getBoolean(ENTITY_DETAILS_KEY)))
+            .setGeoIndexDetails(new 
GeoIndexDetails(basicObj.getBoolean(GEO_DETAILS_KEY)))
+            .setPCJIndexDetails(getPCJDetails(basicObj))
+            .setTemporalIndexDetails(new 
TemporalIndexDetails(basicObj.getBoolean(TEMPORAL_DETAILS_KEY)))
+            .setFreeTextDetails(new 
FreeTextIndexDetails(basicObj.getBoolean(FREETEXT_DETAILS_KEY)))
+            .setProspectorDetails(new 
ProspectorDetails(Optional.<Date>fromNullable(basicObj.getDate(PROSPECTOR_DETAILS_KEY))))
+            .setJoinSelectivityDetails(new 
JoinSelectivityDetails(Optional.<Date>fromNullable(basicObj.getDate(JOIN_SELECTIVITY_DETAILS_KEY))))
+            .build();
+        } catch(final Exception e) {
+            throw new MalformedRyaDetailsException("Failed to make RyaDetail 
from Mongo Object, it is malformed.", e);
+        }
+    }
+
+    private static PCJIndexDetails getPCJDetails(final BasicDBObject basicObj) 
{
+        final BasicDBObject pcjObj = (BasicDBObject) 
basicObj.get(PCJ_DETAILS_KEY);
+        final PCJIndexDetails.Builder pcjBuilder = PCJIndexDetails.builder()
+            .setEnabled(pcjObj.getBoolean(PCJ_ENABLED_KEY))
+            .setFluoDetails(new FluoDetails(pcjObj.getString(PCJ_FLUO_KEY)));
+        final BasicDBList pcjs = (BasicDBList) pcjObj.get(PCJ_PCJS_KEY);
+        if(pcjs != null) {
+            for(int ii = 0; ii < pcjs.size(); ii++) {
+                final BasicDBObject pcj = (BasicDBObject) pcjs.get(ii);
+                pcjBuilder.addPCJDetails(
+                PCJDetails.builder()
+                    .setId(pcj.getString(PCJ_ID_KEY))
+                    
.setUpdateStrategy(PCJUpdateStrategy.valueOf((String)pcj.get(PCJ_UPDATE_STRAT_KEY)))
+                    .setLastUpdateTime(pcj.getDate(PCJ_LAST_UPDATE_KEY))
+                    .build());
+            }
+        }
+        return pcjBuilder.build();
+    }
+
+    /**
+     * Exception thrown when a MongoDB {@link DBObject} is malformed when 
attemptin
+     * to adapt it into a {@link RyaDetails}.
+     */
+    public static class MalformedRyaDetailsException extends Exception {
+        private static final long serialVersionUID = 1L;
+
+        /**
+         * Creates a new {@link MalformedRyaDetailsException}
+         * @param message - The message to be displayed by the exception.
+         * @param e - The source cause of the exception.
+         */
+        public MalformedRyaDetailsException(final String message, final 
Throwable e) {
+            super(message, e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/ec598be4/dao/mongodb.rya/src/main/java/mvm/rya/mongodb/instance/MongoRyaInstanceDetailsRepository.java
----------------------------------------------------------------------
diff --git 
a/dao/mongodb.rya/src/main/java/mvm/rya/mongodb/instance/MongoRyaInstanceDetailsRepository.java
 
b/dao/mongodb.rya/src/main/java/mvm/rya/mongodb/instance/MongoRyaInstanceDetailsRepository.java
new file mode 100644
index 0000000..51ba9c2
--- /dev/null
+++ 
b/dao/mongodb.rya/src/main/java/mvm/rya/mongodb/instance/MongoRyaInstanceDetailsRepository.java
@@ -0,0 +1,125 @@
+package mvm.rya.mongodb.instance;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.Objects.requireNonNull;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
+import com.mongodb.BasicDBObject;
+import com.mongodb.DB;
+import com.mongodb.DBCollection;
+import com.mongodb.DBObject;
+import com.mongodb.MongoClient;
+import com.mongodb.WriteResult;
+
+import mvm.rya.api.instance.RyaDetails;
+import mvm.rya.api.instance.RyaDetailsRepository;
+import 
mvm.rya.mongodb.instance.MongoDetailsAdapter.MalformedRyaDetailsException;
+
+/**
+ * An implementation of {@link RyaDetailsRepository} that stores a Rya
+ * instance's {@link RyaDetails} in a Mongo document.
+ */
+@ParametersAreNonnullByDefault
+public class MongoRyaInstanceDetailsRepository implements RyaDetailsRepository 
{
+    private static final String INSTANCE_DETAILS_COLLECTION_NAME = 
"instance_details";
+
+    private final DB db;
+    private final String instanceName;
+
+    /**
+     * Constructs an instance of {@link MongoRyaInstanceDetailsRepository}.
+     *
+     * @param client - Connects to the instance of Mongo that hosts the Rya 
instance. (not null)
+     * @param instanceName - The name of the Rya instance this repository 
represents. (not null)
+     */
+    public MongoRyaInstanceDetailsRepository(final MongoClient client, final 
String instanceName) {
+        checkNotNull(client);
+        this.instanceName = requireNonNull( instanceName );
+        db = client.getDB(this.instanceName);
+    }
+
+    @Override
+    public boolean isInitialized() throws RyaDetailsRepositoryException {
+        final DBCollection col = 
db.getCollection(INSTANCE_DETAILS_COLLECTION_NAME);
+        return col.count() == 1;
+    }
+
+    @Override
+    public void initialize(final RyaDetails details) throws 
AlreadyInitializedException, RyaDetailsRepositoryException {
+        // Preconditions.
+        requireNonNull( details );
+
+        if(!details.getRyaInstanceName().equals( instanceName )) {
+            throw new RyaDetailsRepositoryException("The instance name that 
was in the provided 'details' does not match " +
+                    "the instance name that this repository is connected to. 
Make sure you're connected to the" +
+                    "correct Rya instance.");
+        }
+
+        if(isInitialized()) {
+            throw new AlreadyInitializedException("The repository has already 
been initialized for the Rya instance named '" +
+                    instanceName + "'.");
+        }
+
+        // Create the document that hosts the details if it has not been 
created yet.
+        final DBCollection col = 
db.createCollection(INSTANCE_DETAILS_COLLECTION_NAME, new BasicDBObject());
+
+        // Write the details to the collection.
+        col.insert(MongoDetailsAdapter.toDBObject(details));
+    }
+
+    @Override
+    public RyaDetails getRyaInstanceDetails() throws NotInitializedException, 
RyaDetailsRepositoryException {
+        // Preconditions.
+        if(!isInitialized()) {
+            throw new NotInitializedException("Could not fetch the details for 
the Rya instanced named '" +
+                    instanceName + "' because it has not been initialized 
yet.");
+        }
+
+        // Fetch the value from the collection.
+        final DBCollection col = 
db.getCollection(INSTANCE_DETAILS_COLLECTION_NAME);
+        //There should only be one document in the collection.
+        final DBObject mongoObj = col.findOne();
+
+        try{
+            // Deserialize it.
+            return MongoDetailsAdapter.toRyaDetails( mongoObj );
+        } catch (final MalformedRyaDetailsException e) {
+            throw new RyaDetailsRepositoryException("The existing details 
details are malformed.", e);
+        }
+    }
+
+    @Override
+    public void update(final RyaDetails oldDetails, final RyaDetails 
newDetails)
+            throws NotInitializedException, ConcurrentUpdateException, 
RyaDetailsRepositoryException {
+        // Preconditions.
+        requireNonNull(oldDetails);
+        requireNonNull(newDetails);
+
+        if(!newDetails.getRyaInstanceName().equals( instanceName )) {
+            throw new RyaDetailsRepositoryException("The instance name that 
was in the provided 'newDetails' does not match " +
+                    "the instance name that this repository is connected to. 
Make sure you're connected to the" +
+                    "correct Rya instance.");
+        }
+
+        if(!isInitialized()) {
+            throw new NotInitializedException("Could not update the details 
for the Rya instanced named '" +
+                    instanceName + "' because it has not been initialized 
yet.");
+        }
+
+        if(oldDetails.equals(newDetails)) {
+            return;
+        }
+
+        final DBCollection col = 
db.getCollection(INSTANCE_DETAILS_COLLECTION_NAME);
+        final DBObject oldObj = MongoDetailsAdapter.toDBObject(oldDetails);
+        final DBObject newObj = MongoDetailsAdapter.toDBObject(newDetails);
+        final WriteResult result = col.update(oldObj, newObj);
+
+        //since there is only 1 document, there should only be 1 update.
+        if(result.getN() != 1) {
+            throw new ConcurrentUpdateException("Could not update the details 
for the Rya instance named '" +
+                instanceName + "' because the old value is out of date.");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/ec598be4/dao/mongodb.rya/src/test/java/mvm/rya/mongodb/instance/MongoDetailsAdapterTest.java
----------------------------------------------------------------------
diff --git 
a/dao/mongodb.rya/src/test/java/mvm/rya/mongodb/instance/MongoDetailsAdapterTest.java
 
b/dao/mongodb.rya/src/test/java/mvm/rya/mongodb/instance/MongoDetailsAdapterTest.java
new file mode 100644
index 0000000..8628dbd
--- /dev/null
+++ 
b/dao/mongodb.rya/src/test/java/mvm/rya/mongodb/instance/MongoDetailsAdapterTest.java
@@ -0,0 +1,230 @@
+package mvm.rya.mongodb.instance;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Date;
+
+import org.junit.Test;
+
+import com.google.common.base.Optional;
+import com.mongodb.BasicDBObject;
+import com.mongodb.DBObject;
+import com.mongodb.util.JSON;
+
+import mvm.rya.api.instance.RyaDetails;
+import mvm.rya.api.instance.RyaDetails.EntityCentricIndexDetails;
+import mvm.rya.api.instance.RyaDetails.FreeTextIndexDetails;
+import mvm.rya.api.instance.RyaDetails.GeoIndexDetails;
+import mvm.rya.api.instance.RyaDetails.JoinSelectivityDetails;
+import mvm.rya.api.instance.RyaDetails.PCJIndexDetails;
+import mvm.rya.api.instance.RyaDetails.PCJIndexDetails.FluoDetails;
+import mvm.rya.api.instance.RyaDetails.PCJIndexDetails.PCJDetails;
+import 
mvm.rya.api.instance.RyaDetails.PCJIndexDetails.PCJDetails.PCJUpdateStrategy;
+import mvm.rya.api.instance.RyaDetails.ProspectorDetails;
+import mvm.rya.api.instance.RyaDetails.TemporalIndexDetails;
+import 
mvm.rya.mongodb.instance.MongoDetailsAdapter.MalformedRyaDetailsException;
+
+public class MongoDetailsAdapterTest {
+    @Test
+    public void ryaDetailsToMongoTest() {
+        final PCJIndexDetails.Builder pcjBuilder = PCJIndexDetails.builder()
+        .setEnabled(true)
+        .setFluoDetails(new FluoDetails("fluo"));
+        for(int ii = 0; ii < 2; ii++) {
+            pcjBuilder.addPCJDetails(
+            PCJDetails.builder()
+            .setId("pcj_"+ii)
+            .setUpdateStrategy(PCJUpdateStrategy.BATCH)
+            .setLastUpdateTime(new Date(ii))
+            .build());
+        }
+
+        final RyaDetails details = RyaDetails.builder()
+        .setRyaInstanceName("test")
+        .setRyaVersion("1")
+        .setEntityCentricIndexDetails(new EntityCentricIndexDetails(true))
+        .setGeoIndexDetails(new GeoIndexDetails(true))
+        .setPCJIndexDetails(pcjBuilder.build())
+        .setTemporalIndexDetails(new TemporalIndexDetails(true))
+        .setFreeTextDetails(new FreeTextIndexDetails(true))
+        .setProspectorDetails(new 
ProspectorDetails(Optional.<Date>fromNullable(new Date(0L))))
+        .setJoinSelectivityDetails(new 
JoinSelectivityDetails(Optional.<Date>fromNullable(new Date(1L))))
+        .build();
+
+        final DBObject expected = (DBObject) JSON.parse(
+            "{ "
+            + "instanceName : \"test\","
+            + "version : \"1\","
+            + "entityCentricDetails : true,"
+            + "geoDetails : true,"
+            + "pcjDetails : {"
+            +    "enabled : true ,"
+            +    "fluoName : \"fluo\","
+            +    "pcjs : [ "
+            +       "{"
+            +          "id : \"pcj_0\","
+            +          "updateStrategy : \"BATCH\","
+            +          "lastUpdate : { $date : \"1970-01-01T00:00:00.000Z\"}"
+            +       "},"
+            +       "{"
+            +          "id : \"pcj_1\","
+            +          "updateStrategy : \"BATCH\","
+            +          "lastUpdate : { $date : \"1970-01-01T00:00:00.001Z\"}"
+            +       "}]"
+            + "},"
+            + "temporalDetails : true,"
+            + "freeTextDetails : true,"
+            + "prospectorDetails : { $date : \"1970-01-01T00:00:00.000Z\"},"
+            + "joinSelectivitiyDetails : { $date : 
\"1970-01-01T00:00:00.001Z\"}"
+          + "}"
+        );
+        final BasicDBObject actual = MongoDetailsAdapter.toDBObject(details);
+        System.out.println(expected.toString());
+        System.out.println("***");
+        System.out.println(actual.toString());
+        assertEquals(expected.toString(), actual.toString());
+    }
+
+    @Test
+    public void mongoToRyaDetailsTest() throws MalformedRyaDetailsException {
+        final BasicDBObject mongo = (BasicDBObject) JSON.parse(
+            "{ "
+            + "instanceName : \"test\","
+            + "version : \"1\","
+            + "entityCentricDetails : true,"
+            + "geoDetails : true,"
+            + "pcjDetails : {"
+            +    "enabled : true ,"
+            +    "fluoName : \"fluo\","
+            +    "pcjs : [ "
+            +       "{"
+            +          "id : \"pcj_0\","
+            +          "updateStrategy : \"BATCH\","
+            +          "lastUpdate : { $date : \"1970-01-01T00:00:00.000Z\"}"
+            +       "},"
+            +       "{"
+            +          "id : \"pcj_1\","
+            +          "updateStrategy : \"BATCH\","
+            +          "lastUpdate : { $date : \"1970-01-01T00:00:00.001Z\"}"
+            +       "}]"
+            + "},"
+            + "temporalDetails : true,"
+            + "freeTextDetails : true,"
+            + "prospectorDetails : { $date : \"1970-01-01T00:00:00.000Z\"},"
+            + "joinSelectivitiyDetails : { $date : 
\"1970-01-01T00:00:00.001Z\"}"
+          + "}"
+        );
+        final PCJIndexDetails.Builder pcjBuilder = PCJIndexDetails.builder()
+        .setEnabled(true)
+        .setFluoDetails(new FluoDetails("fluo"));
+        for(int ii = 0; ii < 2; ii++) {
+            pcjBuilder.addPCJDetails(
+            PCJDetails.builder()
+            .setId("pcj_"+ii)
+            .setUpdateStrategy(PCJUpdateStrategy.BATCH)
+            .setLastUpdateTime(new Date(ii))
+            .build());
+        }
+
+        final RyaDetails expected = RyaDetails.builder()
+        .setRyaInstanceName("test")
+        .setRyaVersion("1")
+        .setEntityCentricIndexDetails(new EntityCentricIndexDetails(true))
+        .setGeoIndexDetails(new GeoIndexDetails(true))
+        .setPCJIndexDetails(pcjBuilder.build())
+        .setTemporalIndexDetails(new TemporalIndexDetails(true))
+        .setFreeTextDetails(new FreeTextIndexDetails(true))
+        .setProspectorDetails(new 
ProspectorDetails(Optional.<Date>fromNullable(new Date(0L))))
+        .setJoinSelectivityDetails(new 
JoinSelectivityDetails(Optional.<Date>fromNullable(new Date(1L))))
+        .build();
+
+        final RyaDetails actual = MongoDetailsAdapter.toRyaDetails(mongo);
+        assertEquals(expected, actual);
+    }
+
+    @Test
+    public void absentOptionalToRyaDetailsTest() throws 
MalformedRyaDetailsException {
+        final BasicDBObject mongo = (BasicDBObject) JSON.parse(
+                "{ "
+                + "instanceName : \"test\","
+                + "version : \"1\","
+                + "entityCentricDetails : true,"
+                + "geoDetails : false,"
+                + "pcjDetails : {"
+                +    "enabled : false,"
+                +    "fluoName : \"fluo\","
+                +    "pcjs : [ "
+                +       "{"
+                +          "id : \"pcj_1\","
+                +          "updateStrategy : \"INCREMENTAL\""
+                +       "}"
+                +    "]"
+                + "},"
+                + "temporalDetails : false,"
+                + "freeTextDetails : true,"
+                + "prospectorDetails : null,"
+                + "joinSelectivitiyDetails : null"
+              + "}"
+            );
+        final PCJIndexDetails.Builder pcjBuilder = PCJIndexDetails.builder()
+        .setEnabled(false)
+        .setFluoDetails(new FluoDetails("fluo"))
+        .addPCJDetails(
+            PCJDetails.builder()
+            .setId("pcj_1")
+            .setUpdateStrategy(PCJUpdateStrategy.INCREMENTAL)
+            .setLastUpdateTime(null).build());
+
+        final RyaDetails expected = RyaDetails.builder()
+        .setRyaInstanceName("test")
+        .setRyaVersion("1")
+        .setEntityCentricIndexDetails(new EntityCentricIndexDetails(true))
+        .setGeoIndexDetails(new GeoIndexDetails(false))
+        .setPCJIndexDetails(pcjBuilder.build())
+        .setTemporalIndexDetails(new TemporalIndexDetails(false))
+        .setFreeTextDetails(new FreeTextIndexDetails(true))
+        .setProspectorDetails(new ProspectorDetails(Optional.<Date>absent()))
+        .setJoinSelectivityDetails(new 
JoinSelectivityDetails(Optional.<Date>absent()))
+        .build();
+
+        final RyaDetails actual = MongoDetailsAdapter.toRyaDetails(mongo);
+        assertEquals(expected, actual);
+    }
+
+    @Test
+    public void absentOptionalToMongoTest() {
+        final BasicDBObject expected = (BasicDBObject) JSON.parse(
+                "{ "
+                + "instanceName : \"test\","
+                + "version : \"1\","
+                + "entityCentricDetails : true,"
+                + "geoDetails : false,"
+                + "pcjDetails : {"
+                +    "enabled : true,"
+                +    "fluoName : \"fluo\","
+                +    "pcjs : [ ]"
+                + "},"
+                + "temporalDetails : false,"
+                + "freeTextDetails : true"
+              + "}"
+            );
+        final PCJIndexDetails.Builder pcjBuilder = PCJIndexDetails.builder()
+        .setEnabled(true)
+        .setFluoDetails(new FluoDetails("fluo"));
+
+        final RyaDetails details = RyaDetails.builder()
+        .setRyaInstanceName("test")
+        .setRyaVersion("1")
+        .setEntityCentricIndexDetails(new EntityCentricIndexDetails(true))
+        .setGeoIndexDetails(new GeoIndexDetails(false))
+        .setPCJIndexDetails(pcjBuilder.build())
+        .setTemporalIndexDetails(new TemporalIndexDetails(false))
+        .setFreeTextDetails(new FreeTextIndexDetails(true))
+        .setProspectorDetails(new ProspectorDetails(Optional.<Date>absent()))
+        .setJoinSelectivityDetails(new 
JoinSelectivityDetails(Optional.<Date>absent()))
+        .build();
+
+        final DBObject actual = MongoDetailsAdapter.toDBObject(details);
+        assertEquals(expected, actual);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/ec598be4/dao/mongodb.rya/src/test/java/mvm/rya/mongodb/instance/MongoRyaDetailsRepositoryIT.java
----------------------------------------------------------------------
diff --git 
a/dao/mongodb.rya/src/test/java/mvm/rya/mongodb/instance/MongoRyaDetailsRepositoryIT.java
 
b/dao/mongodb.rya/src/test/java/mvm/rya/mongodb/instance/MongoRyaDetailsRepositoryIT.java
new file mode 100644
index 0000000..05dab7e
--- /dev/null
+++ 
b/dao/mongodb.rya/src/test/java/mvm/rya/mongodb/instance/MongoRyaDetailsRepositoryIT.java
@@ -0,0 +1,325 @@
+package mvm.rya.mongodb.instance;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.Date;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.google.common.base.Optional;
+import com.mongodb.DB;
+import com.mongodb.MongoClient;
+import com.mongodb.MongoException;
+
+import de.flapdoodle.embed.mongo.tests.MongodForTestsFactory;
+import mvm.rya.api.instance.RyaDetails;
+import mvm.rya.api.instance.RyaDetails.EntityCentricIndexDetails;
+import mvm.rya.api.instance.RyaDetails.FreeTextIndexDetails;
+import mvm.rya.api.instance.RyaDetails.GeoIndexDetails;
+import mvm.rya.api.instance.RyaDetails.JoinSelectivityDetails;
+import mvm.rya.api.instance.RyaDetails.PCJIndexDetails;
+import mvm.rya.api.instance.RyaDetails.PCJIndexDetails.FluoDetails;
+import mvm.rya.api.instance.RyaDetails.PCJIndexDetails.PCJDetails;
+import 
mvm.rya.api.instance.RyaDetails.PCJIndexDetails.PCJDetails.PCJUpdateStrategy;
+import mvm.rya.api.instance.RyaDetails.ProspectorDetails;
+import mvm.rya.api.instance.RyaDetails.TemporalIndexDetails;
+import mvm.rya.api.instance.RyaDetailsRepository;
+import mvm.rya.api.instance.RyaDetailsRepository.AlreadyInitializedException;
+import mvm.rya.api.instance.RyaDetailsRepository.ConcurrentUpdateException;
+import mvm.rya.api.instance.RyaDetailsRepository.NotInitializedException;
+import mvm.rya.api.instance.RyaDetailsRepository.RyaDetailsRepositoryException;
+
+/**
+ * Tests the methods of {@link AccumuloRyaDetailsRepository} by using a {@link 
MiniAccumuloCluster}.
+ */
+public class MongoRyaDetailsRepositoryIT {
+
+    private static MongoClient client = null;
+    private static DB testDB = null;
+    @BeforeClass
+    public static void startMiniAccumulo() throws MongoException, IOException {
+        final MongodForTestsFactory mongoFactory = new MongodForTestsFactory();
+        client = mongoFactory.newMongo();
+    }
+
+    @Before
+    public void clearLastTest() {
+        client.dropDatabase("testInstance");
+        testDB = client.getDB("testInstance");
+    }
+
+    @AfterClass
+    public static void stopMiniAccumulo() throws IOException, 
InterruptedException {
+        client.close();
+    }
+
+    @Test
+    public void initializeAndGet() throws AlreadyInitializedException, 
RyaDetailsRepositoryException {
+        final String instanceName = "testInstance";
+
+        // Create the metadata object the repository will be initialized with.
+        final RyaDetails details = RyaDetails.builder()
+            .setRyaInstanceName(instanceName)
+            .setRyaVersion("1.2.3.4")
+            .setEntityCentricIndexDetails( new EntityCentricIndexDetails(true) 
)
+            .setGeoIndexDetails( new GeoIndexDetails(true) )
+            .setTemporalIndexDetails( new TemporalIndexDetails(true) )
+            .setFreeTextDetails( new FreeTextIndexDetails(true) )
+            .setPCJIndexDetails(
+                    PCJIndexDetails.builder()
+                        .setEnabled(true)
+                        .setFluoDetails( new 
FluoDetails("test_instance_rya_pcj_updater") )
+                        .addPCJDetails(
+                                PCJDetails.builder()
+                                    .setId("pcj 1")
+                                    .setUpdateStrategy(PCJUpdateStrategy.BATCH)
+                                    .setLastUpdateTime( new Date() )
+                                    .build())
+                        .addPCJDetails(
+                                PCJDetails.builder()
+                                    .setId("pcj 2")
+                                    
.setUpdateStrategy(PCJUpdateStrategy.INCREMENTAL)
+                                    .build())
+                        .build())
+            .setProspectorDetails( new ProspectorDetails(Optional.of(new 
Date())) )
+            .setJoinSelectivityDetails( new 
JoinSelectivityDetails(Optional.of(new Date())) )
+            .build();
+
+        // Setup the repository that will be tested using a mock instance of 
MongoDB.
+        final RyaDetailsRepository repo = new 
MongoRyaInstanceDetailsRepository(client, instanceName);
+
+        // Initialize the repository
+        repo.initialize(details);
+
+        // Fetch the stored details.
+        final RyaDetails stored = repo.getRyaInstanceDetails();
+
+        // Ensure the fetched object is equivalent to what was stored.
+        assertEquals(details, stored);
+    }
+
+    @Test(expected = AlreadyInitializedException.class)
+    public void initialize_alreadyInitialized() throws 
AlreadyInitializedException, RyaDetailsRepositoryException {
+        final String instanceName = "testInstance";
+
+        // Create the metadata object the repository will be initialized with.
+        final RyaDetails details = RyaDetails.builder()
+            .setRyaInstanceName(instanceName)
+            .setRyaVersion("1.2.3.4")
+            .setEntityCentricIndexDetails( new EntityCentricIndexDetails(true) 
)
+            .setGeoIndexDetails( new GeoIndexDetails(true) )
+            .setTemporalIndexDetails( new TemporalIndexDetails(true) )
+            .setFreeTextDetails( new FreeTextIndexDetails(true) )
+            .setPCJIndexDetails(
+                    PCJIndexDetails.builder()
+                        .setEnabled(true)
+                        .setFluoDetails( new 
FluoDetails("test_instance_rya_pcj_updater") )
+                        .addPCJDetails(
+                                PCJDetails.builder()
+                                    .setId("pcj 1")
+                                    .setUpdateStrategy(PCJUpdateStrategy.BATCH)
+                                    .setLastUpdateTime( new Date() )
+                                    .build())
+                        .addPCJDetails(
+                                PCJDetails.builder()
+                                    .setId("pcj 2")
+                                    
.setUpdateStrategy(PCJUpdateStrategy.INCREMENTAL)
+                                    .build())
+                        .build())
+            .setProspectorDetails( new ProspectorDetails(Optional.of(new 
Date())) )
+            .setJoinSelectivityDetails( new 
JoinSelectivityDetails(Optional.of(new Date())) )
+            .build();
+
+        // Setup the repository that will be tested using a mock instance of 
MongoDB.
+        final RyaDetailsRepository repo = new 
MongoRyaInstanceDetailsRepository(client, instanceName);
+
+        // Initialize the repository
+        repo.initialize(details);
+
+        // Initialize it again.
+        repo.initialize(details);
+    }
+
+    @Test(expected = NotInitializedException.class)
+    public void getRyaInstance_notInitialized() throws 
NotInitializedException, RyaDetailsRepositoryException {
+        // Setup the repository that will be tested using a mock instance of 
Accumulo.
+        final RyaDetailsRepository repo = new 
MongoRyaInstanceDetailsRepository(client, "testInstance");
+
+        // Try to fetch the details from the uninitialized repository.
+        repo.getRyaInstanceDetails();
+    }
+
+    @Test
+    public void isInitialized_true() throws AlreadyInitializedException, 
RyaDetailsRepositoryException {
+        final String instanceName = "testInstance";
+
+        // Create the metadata object the repository will be initialized with.
+        final RyaDetails details = RyaDetails.builder()
+            .setRyaInstanceName(instanceName)
+            .setRyaVersion("1.2.3.4")
+            .setEntityCentricIndexDetails( new EntityCentricIndexDetails(true) 
)
+            .setGeoIndexDetails( new GeoIndexDetails(true) )
+            .setTemporalIndexDetails( new TemporalIndexDetails(true) )
+            .setFreeTextDetails( new FreeTextIndexDetails(true) )
+            .setPCJIndexDetails(
+                    PCJIndexDetails.builder()
+                        .setEnabled(true)
+                        .setFluoDetails( new 
FluoDetails("test_instance_rya_pcj_updater") )
+                        .addPCJDetails(
+                                PCJDetails.builder()
+                                    .setId("pcj 1")
+                                    .setUpdateStrategy(PCJUpdateStrategy.BATCH)
+                                    .setLastUpdateTime( new Date() )
+                                    .build())
+                        .addPCJDetails(
+                                PCJDetails.builder()
+                                    .setId("pcj 2")
+                                    
.setUpdateStrategy(PCJUpdateStrategy.INCREMENTAL)
+                                    .build())
+                        .build())
+            .setProspectorDetails( new ProspectorDetails(Optional.of(new 
Date())) )
+            .setJoinSelectivityDetails( new 
JoinSelectivityDetails(Optional.of(new Date())) )
+            .build();
+
+        // Setup the repository that will be tested using a mock instance of 
MongoDB.
+        final RyaDetailsRepository repo = new 
MongoRyaInstanceDetailsRepository(client, "testInstance");
+
+        // Initialize the repository
+        repo.initialize(details);
+
+        // Ensure the repository reports that it has been initialized.
+        assertTrue( repo.isInitialized() );
+    }
+
+    @Test
+    public void isInitialized_false() throws RyaDetailsRepositoryException {
+        // Setup the repository that will be tested using a mock instance of 
MongoDB.
+        final RyaDetailsRepository repo = new 
MongoRyaInstanceDetailsRepository(client, "testInstance");
+
+        // Ensure the repository reports that is has not been initialized.
+        assertFalse( repo.isInitialized() );
+    }
+
+    @Test
+    public void update() throws AlreadyInitializedException, 
RyaDetailsRepositoryException {
+        final String instanceName = "testInstance";
+
+        // Create the metadata object the repository will be initialized with.
+        final RyaDetails details = RyaDetails.builder()
+            .setRyaInstanceName(instanceName)
+            .setRyaVersion("1.2.3.4")
+            .setEntityCentricIndexDetails( new EntityCentricIndexDetails(true) 
)
+            .setGeoIndexDetails( new GeoIndexDetails(true) )
+            .setTemporalIndexDetails( new TemporalIndexDetails(true) )
+            .setFreeTextDetails( new FreeTextIndexDetails(true) )
+            .setPCJIndexDetails(
+                    PCJIndexDetails.builder()
+                        .setEnabled(true)
+                        .setFluoDetails( new 
FluoDetails("test_instance_rya_pcj_updater") )
+                        .addPCJDetails(
+                                PCJDetails.builder()
+                                    .setId("pcj 1")
+                                    .setUpdateStrategy(PCJUpdateStrategy.BATCH)
+                                    .setLastUpdateTime( new Date() )
+                                    .build())
+                        .addPCJDetails(
+                                PCJDetails.builder()
+                                    .setId("pcj 2")
+                                    
.setUpdateStrategy(PCJUpdateStrategy.INCREMENTAL)
+                                    .build())
+                        .build())
+            .setProspectorDetails( new ProspectorDetails(Optional.of(new 
Date())) )
+            .setJoinSelectivityDetails( new 
JoinSelectivityDetails(Optional.of(new Date())) )
+            .build();
+
+        // Setup the repository that will be tested using a mock instance of 
MongoDB.
+        final RyaDetailsRepository repo = new 
MongoRyaInstanceDetailsRepository(client, "testInstance");
+
+        // Initialize the repository
+        repo.initialize(details);
+
+        // Create a new state for the details.
+        final RyaDetails updated = new RyaDetails.Builder( details )
+                .setGeoIndexDetails( new GeoIndexDetails(false) )
+                .build();
+
+        // Execute the update.
+        repo.update(details, updated);
+
+        // Show the new state that is stored matches the updated state.
+        final RyaDetails fetched = repo.getRyaInstanceDetails();
+        assertEquals(updated, fetched);
+    }
+
+    @Test(expected = ConcurrentUpdateException.class)
+    public void update_outOfDate() throws AlreadyInitializedException, 
RyaDetailsRepositoryException {
+        final String instanceName = "testInstance";
+
+        // Create the metadata object the repository will be initialized with.
+        final RyaDetails details = RyaDetails.builder()
+            .setRyaInstanceName(instanceName)
+            .setRyaVersion("1.2.3.4")
+            .setEntityCentricIndexDetails( new EntityCentricIndexDetails(true) 
)
+            .setGeoIndexDetails( new GeoIndexDetails(true) )
+            .setTemporalIndexDetails( new TemporalIndexDetails(true) )
+            .setFreeTextDetails( new FreeTextIndexDetails(true) )
+            .setPCJIndexDetails(
+                    PCJIndexDetails.builder()
+                        .setEnabled(true)
+                        .setFluoDetails( new 
FluoDetails("test_instance_rya_pcj_updater") )
+                        .addPCJDetails(
+                                PCJDetails.builder()
+                                    .setId("pcj 1")
+                                    .setUpdateStrategy(PCJUpdateStrategy.BATCH)
+                                    .setLastUpdateTime( new Date() )
+                                    .build())
+                        .addPCJDetails(
+                                PCJDetails.builder()
+                                    .setId("pcj 2")
+                                    
.setUpdateStrategy(PCJUpdateStrategy.INCREMENTAL)
+                                    .build())
+                        .build())
+            .setProspectorDetails( new ProspectorDetails(Optional.of(new 
Date())) )
+            .setJoinSelectivityDetails( new 
JoinSelectivityDetails(Optional.of(new Date())) )
+            .build();
+
+        // Setup the repository that will be tested using a mock instance of 
MongoDB.
+        final RyaDetailsRepository repo = new 
MongoRyaInstanceDetailsRepository(client, "testInstance");
+
+        // Initialize the repository
+        repo.initialize(details);
+
+        // Create a new state for the details.
+        final RyaDetails updated = new RyaDetails.Builder( details )
+                .setGeoIndexDetails( new GeoIndexDetails(false) )
+                .build();
+
+        // Try to execute the update where the old state is not the currently 
stored state.
+        repo.update(updated, updated);
+    }
+}
\ No newline at end of file


Reply via email to