http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/c2a09dec/extras/indexing/src/main/java/mvm/rya/indexing/entity/storage/mongo/RyaTypeDocumentConverter.java
----------------------------------------------------------------------
diff --git 
a/extras/indexing/src/main/java/mvm/rya/indexing/entity/storage/mongo/RyaTypeDocumentConverter.java
 
b/extras/indexing/src/main/java/mvm/rya/indexing/entity/storage/mongo/RyaTypeDocumentConverter.java
new file mode 100644
index 0000000..ab6148b
--- /dev/null
+++ 
b/extras/indexing/src/main/java/mvm/rya/indexing/entity/storage/mongo/RyaTypeDocumentConverter.java
@@ -0,0 +1,69 @@
+/**
+ * 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.
+ */
+package mvm.rya.indexing.entity.storage.mongo;
+
+import static java.util.Objects.requireNonNull;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
+import org.bson.Document;
+import org.openrdf.model.ValueFactory;
+import org.openrdf.model.impl.ValueFactoryImpl;
+
+import mvm.rya.api.domain.RyaType;
+
+/**
+ * Converts between {@link RyaType} and {@link Document}.
+ */
+@ParametersAreNonnullByDefault
+public class RyaTypeDocumentConverter implements DocumentConverter<RyaType> {
+
+    private static final ValueFactory VF = new ValueFactoryImpl();
+
+    public static final String DATA_TYPE = "dataType";
+    public static final String VALUE = "value";
+
+    @Override
+    public Document toDocument(RyaType ryaType) {
+        requireNonNull(ryaType);
+
+        return new Document()
+                .append(DATA_TYPE, ryaType.getDataType().toString())
+                .append(VALUE, ryaType.getData());
+    }
+
+    @Override
+    public RyaType fromDocument(Document document) throws 
DocumentConverterException {
+        requireNonNull(document);
+
+        if(!document.containsKey(DATA_TYPE)) {
+            throw new DocumentConverterException("Could not convert document 
'" + document +
+                    "' because its '" + DATA_TYPE + "' field is missing.");
+        }
+
+        if(!document.containsKey(VALUE)) {
+            throw new DocumentConverterException("Could not convert document 
'" + document +
+                    "' because its '" + VALUE + "' field is missing.");
+        }
+
+        return new RyaType(
+                VF.createURI( document.getString(DATA_TYPE) ),
+                document.getString(VALUE));
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/c2a09dec/extras/indexing/src/main/java/mvm/rya/indexing/entity/storage/mongo/TypeDocumentConverter.java
----------------------------------------------------------------------
diff --git 
a/extras/indexing/src/main/java/mvm/rya/indexing/entity/storage/mongo/TypeDocumentConverter.java
 
b/extras/indexing/src/main/java/mvm/rya/indexing/entity/storage/mongo/TypeDocumentConverter.java
new file mode 100644
index 0000000..2d171d7
--- /dev/null
+++ 
b/extras/indexing/src/main/java/mvm/rya/indexing/entity/storage/mongo/TypeDocumentConverter.java
@@ -0,0 +1,80 @@
+/**
+ * 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.
+ */
+package mvm.rya.indexing.entity.storage.mongo;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
+import org.bson.Document;
+
+import com.google.common.collect.ImmutableSet;
+
+import mvm.rya.api.domain.RyaURI;
+import mvm.rya.indexing.entity.model.Type;
+
+/**
+ * Converts between {@link Type} and {@link Document}.
+ */
+@ParametersAreNonnullByDefault
+public class TypeDocumentConverter implements DocumentConverter<Type> {
+
+    public static final String ID = "_id";
+    public static final String PROPERTY_NAMES = "propertyNames";
+
+    @Override
+    public Document toDocument(final Type type) {
+        requireNonNull(type);
+
+        final Document doc = new Document();
+        doc.append(ID, type.getId().getData());
+
+        final List<String> propertyNames = new ArrayList<>();
+        type.getPropertyNames().forEach(field -> 
propertyNames.add(field.getData()));
+        doc.append(PROPERTY_NAMES, propertyNames);
+
+        return doc;
+    }
+
+    @Override
+    public Type fromDocument(final Document document) throws 
DocumentConverterException {
+        requireNonNull(document);
+
+        if(!document.containsKey(ID)) {
+            throw new DocumentConverterException("Could not convert document 
'" + document +
+                    "' because its '" + ID + "' field is missing.");
+        }
+
+        if(!document.containsKey(PROPERTY_NAMES)) {
+            throw new DocumentConverterException("Could not convert document 
'" + document +
+                    "' because its '" + PROPERTY_NAMES + "' field is 
missing.");
+        }
+
+        final RyaURI typeId = new RyaURI( document.getString(ID) );
+
+        final ImmutableSet.Builder<RyaURI> propertyNames = 
ImmutableSet.builder();
+        ((List<String>) document.get(PROPERTY_NAMES))
+            .forEach(propertyName -> propertyNames.add(new 
RyaURI(propertyName)));
+
+        return new Type(typeId, propertyNames.build());
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/c2a09dec/extras/indexing/src/main/java/mvm/rya/indexing/entity/update/BaseEntityIndexer.java
----------------------------------------------------------------------
diff --git 
a/extras/indexing/src/main/java/mvm/rya/indexing/entity/update/BaseEntityIndexer.java
 
b/extras/indexing/src/main/java/mvm/rya/indexing/entity/update/BaseEntityIndexer.java
new file mode 100644
index 0000000..627b879
--- /dev/null
+++ 
b/extras/indexing/src/main/java/mvm/rya/indexing/entity/update/BaseEntityIndexer.java
@@ -0,0 +1,266 @@
+/**
+ * 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.
+ */
+package mvm.rya.indexing.entity.update;
+
+import static com.google.common.base.Preconditions.checkState;
+import static java.util.Collections.singleton;
+import static java.util.Objects.requireNonNull;
+import static java.util.stream.Collectors.groupingBy;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.annotation.Nullable;
+import javax.annotation.ParametersAreNonnullByDefault;
+
+import org.apache.hadoop.conf.Configuration;
+import org.openrdf.model.URI;
+import org.openrdf.model.vocabulary.RDF;
+
+import com.google.common.base.Objects;
+
+import mvm.rya.api.domain.RyaStatement;
+import mvm.rya.api.domain.RyaType;
+import mvm.rya.api.domain.RyaURI;
+import mvm.rya.indexing.entity.model.Entity;
+import mvm.rya.indexing.entity.model.Property;
+import mvm.rya.indexing.entity.model.Type;
+import mvm.rya.indexing.entity.storage.CloseableIterator;
+import mvm.rya.indexing.entity.storage.EntityStorage;
+import mvm.rya.indexing.entity.storage.EntityStorage.EntityStorageException;
+import mvm.rya.indexing.entity.storage.TypeStorage;
+import mvm.rya.indexing.entity.storage.TypeStorage.TypeStorageException;
+import mvm.rya.mongodb.MongoDBRdfConfiguration;
+
+/**
+ * A base class that may be used to update an {@link EntityStorage} as new
+ * {@link RyaStatement}s are added to/removed from the Rya instance.
+ */
+@ParametersAreNonnullByDefault
+public abstract class BaseEntityIndexer implements EntityIndexer {
+
+    /**
+     * When this URI is the Predicate of a Statement, it indicates a {@link 
Type} for an {@link Entity}.
+     */
+    private static final RyaURI TYPE_URI = new RyaURI( RDF.TYPE.toString() );
+
+    private final AtomicReference<MongoDBRdfConfiguration> configuration = new 
AtomicReference<>();
+    private final AtomicReference<EntityStorage> entities = new 
AtomicReference<>();
+    private final AtomicReference<TypeStorage> types = new AtomicReference<>();
+
+    /**
+     * Creates the {@link EntityStorage} that will be used by the indexer.
+     *
+     * @param conf - Indicates how the {@link EntityStorage} is initialized. 
(not null)
+     * @return The {@link EntityStorage} that will be used by this indexer.
+     */
+    public abstract @Nullable EntityStorage getEntityStorage(Configuration 
conf);
+
+    /**
+     * Creates the {@link TypeStorage} that will be used by the indexer.
+     *
+     * @param conf - Indicates how the {@link TypeStorage} is initialized. 
(not null)
+     * @return The {@link TypeStorage} that will be used by this indexer.
+     */
+    public abstract @Nullable TypeStorage getTypeStorage(Configuration conf);
+
+    @Override
+    public void setConf(Configuration conf) {
+        requireNonNull(conf);
+        entities.set( getEntityStorage(conf) );
+        types.set( getTypeStorage(conf) );
+    }
+
+    @Override
+    public Configuration getConf() {
+        return configuration.get();
+    }
+
+    @Override
+    public void storeStatement(RyaStatement statement) throws IOException {
+        requireNonNull(statement);
+        storeStatements( singleton(statement) );
+    }
+
+    @Override
+    public void storeStatements(Collection<RyaStatement> statements) throws 
IOException {
+        requireNonNull(statements);
+
+        final Map<RyaURI,List<RyaStatement>> groupedBySubject = 
statements.stream()
+            .collect(groupingBy(RyaStatement::getSubject));
+
+        for(final Entry<RyaURI, List<RyaStatement>> entry : 
groupedBySubject.entrySet()) {
+            try {
+                updateEntity(entry.getKey(), entry.getValue());
+            } catch (final EntityStorageException e) {
+                throw new IOException("Failed to update the Entity index.", e);
+            }
+        }
+    }
+
+    /**
+     * Updates a {@link Entity} to reflect new {@link RyaStatement}s.
+     *
+     * @param subject - The Subject of the {@link Entity} the statements are 
for. (not null)
+     * @param statements - Statements that the {@link Entity} will be updated 
with. (not null)
+     */
+    private void updateEntity(final RyaURI subject, final 
Collection<RyaStatement> statements) throws EntityStorageException {
+        requireNonNull(subject);
+        requireNonNull(statements);
+
+        final EntityStorage entities = this.entities.get();
+        final TypeStorage types = this.types.get();
+        checkState(entities != null, "Must set this indexers configuration 
before storing statements.");
+        checkState(types != null, "Must set this indexers configuration before 
storing statements.");
+
+        new EntityUpdater(entities).update(subject, old -> {
+            // Create a builder with the updated Version.
+            final Entity.Builder updated;
+            if(!old.isPresent()) {
+                updated = Entity.builder()
+                        .setSubject(subject)
+                        .setVersion(0);
+            } else {
+                final int updatedVersion = old.get().getVersion() + 1;
+                updated = Entity.builder(old.get())
+                        .setVersion( updatedVersion );
+            }
+
+            // Update the entity based on the Statements.
+            for(final RyaStatement statement : statements) {
+
+                // The Statement is setting an Explicit Type ID for the Entity.
+                if(Objects.equal(TYPE_URI, statement.getPredicate())) {
+                    final RyaURI typeId = new 
RyaURI(statement.getObject().getData());
+                    updated.setExplicitType(typeId);
+                }
+
+                // The Statement is adding a Property to the Entity.
+                else {
+                    final RyaURI propertyName = statement.getPredicate();
+                    final RyaType propertyValue = statement.getObject();
+
+                    try(final CloseableIterator<Type> typesIt = 
types.search(propertyName)) {
+                        // Set the Property for each type that includes the 
Statement's predicate.
+                        while(typesIt.hasNext()) {
+                            final RyaURI typeId = typesIt.next().getId();
+                            updated.setProperty(typeId, new 
Property(propertyName, propertyValue));
+                        }
+                    } catch (final TypeStorageException | IOException e) {
+                        throw new RuntimeException("Failed to fetch Types that 
include the property name '" +
+                                statement.getPredicate().getData() + "'.", e);
+                    }
+                }
+            }
+
+            return Optional.of( updated.build() );
+        });
+    }
+
+    @Override
+    public void deleteStatement(RyaStatement statement) throws IOException {
+        requireNonNull(statement);
+
+        final EntityStorage entities = this.entities.get();
+        final TypeStorage types = this.types.get();
+        checkState(entities != null, "Must set this indexers configuration 
before storing statements.");
+        checkState(types != null, "Must set this indexers configuration before 
storing statements.");
+
+        try {
+            new EntityUpdater(entities).update(statement.getSubject(), old -> {
+                // If there is no Entity for the subject of the statement, 
then do nothing.
+                if(!old.isPresent()) {
+                    return Optional.empty();
+                }
+
+                final Entity oldEntity = old.get();
+
+                // Increment the version of the Entity.
+                final Entity.Builder updated = Entity.builder(oldEntity);
+                updated.setVersion(oldEntity.getVersion() + 1);
+
+                if(TYPE_URI.equals(statement.getPredicate())) {
+                    // If the Type ID already isn't in the list of explicit 
types, then do nothing.
+                    final RyaURI typeId = new RyaURI( 
statement.getObject().getData() );
+                    if(!oldEntity.getExplicitTypeIds().contains(typeId)) {
+                        return Optional.empty();
+                    }
+
+                    // Otherwise remove it from the list.
+                    updated.unsetExplicitType(typeId);
+                } else {
+                    // If the deleted property appears within the old entity's 
properties, then remove it.
+                    final RyaURI deletedPropertyName = 
statement.getPredicate();
+
+                    boolean propertyWasPresent = false;
+                    for(final RyaURI typeId : 
oldEntity.getProperties().keySet()) {
+                        for(final RyaURI propertyName : 
oldEntity.getProperties().get(typeId).keySet()) {
+                            if(deletedPropertyName.equals(propertyName)) {
+                                propertyWasPresent = true;
+                                updated.unsetProperty(typeId, 
deletedPropertyName);
+                            }
+                        }
+                    }
+
+                    // If no properties were removed, then do nothing.
+                    if(!propertyWasPresent) {
+                        return Optional.empty();
+                    }
+                }
+
+                return Optional.of( updated.build() );
+            });
+        } catch (final EntityStorageException e) {
+            throw new IOException("Failed to update the Entity index.", e);
+        }
+    }
+
+    @Override
+    public String getTableName() {
+        // Storage details have been abstracted away from the indexer.
+        return null;
+    }
+
+    @Override
+    public void flush() throws IOException {
+        // We do not need to do anything to flush since we do not batch work.
+    }
+
+    @Override
+    public void close() throws IOException {
+        // Nothing to close.
+    }
+
+    @Override
+    public void dropGraph(RyaURI... graphs) {
+        // We do not support graphs when performing entity centric indexing.
+    }
+
+    @Override
+    public Set<URI> getIndexablePredicates() {
+        // This isn't used anywhere in Rya, so it will not be implemented.
+        return null;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/c2a09dec/extras/indexing/src/main/java/mvm/rya/indexing/entity/update/EntityIndexer.java
----------------------------------------------------------------------
diff --git 
a/extras/indexing/src/main/java/mvm/rya/indexing/entity/update/EntityIndexer.java
 
b/extras/indexing/src/main/java/mvm/rya/indexing/entity/update/EntityIndexer.java
new file mode 100644
index 0000000..6d74836
--- /dev/null
+++ 
b/extras/indexing/src/main/java/mvm/rya/indexing/entity/update/EntityIndexer.java
@@ -0,0 +1,31 @@
+/**
+ * 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.
+ */
+package mvm.rya.indexing.entity.update;
+
+import mvm.rya.api.domain.RyaStatement;
+import mvm.rya.api.persist.index.RyaSecondaryIndexer;
+import mvm.rya.indexing.entity.storage.EntityStorage;
+
+/**
+ * Updates the {@link Entity}s that are in a {@link EntityStorage} when new
+ * {@link RyaStatement}s are added/removed from the Rya instance.
+ */
+public interface EntityIndexer extends RyaSecondaryIndexer {
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/c2a09dec/extras/indexing/src/main/java/mvm/rya/indexing/entity/update/EntityUpdater.java
----------------------------------------------------------------------
diff --git 
a/extras/indexing/src/main/java/mvm/rya/indexing/entity/update/EntityUpdater.java
 
b/extras/indexing/src/main/java/mvm/rya/indexing/entity/update/EntityUpdater.java
new file mode 100644
index 0000000..6f883d4
--- /dev/null
+++ 
b/extras/indexing/src/main/java/mvm/rya/indexing/entity/update/EntityUpdater.java
@@ -0,0 +1,121 @@
+/**
+ * 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.
+ */
+package mvm.rya.indexing.entity.update;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.Optional;
+import java.util.function.Function;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
+import mvm.rya.api.domain.RyaURI;
+import mvm.rya.indexing.entity.model.Entity;
+import mvm.rya.indexing.entity.storage.EntityStorage;
+import 
mvm.rya.indexing.entity.storage.EntityStorage.EntityAlreadyExistsException;
+import mvm.rya.indexing.entity.storage.EntityStorage.EntityStorageException;
+import mvm.rya.indexing.entity.storage.EntityStorage.StaleUpdateException;
+
+/**
+ * Performs update operations over an {@link EntityStorage}.
+ */
+@ParametersAreNonnullByDefault
+public class EntityUpdater {
+
+    private final EntityStorage storage;
+
+    /**
+     * Constructs an instance of {@link EntityUpdater}.
+     *
+     * @param storage - The storage this updater operates over. (not null)
+     */
+    public EntityUpdater(EntityStorage storage) {
+        this.storage = requireNonNull(storage);
+    }
+
+    /**
+     * Tries to updates the state of an {@link Entity} until the update 
succeeds
+     * or a non-recoverable exception is thrown.
+     *
+     * @param subject - The Subject of the {@link Entity} that will be 
updated. (not null)
+     * @param mutator - Performs the mutation on the old state of the Entity 
and returns
+     *   the new state of the Entity. (not null)
+     * @throws EntityStorageException A non-recoverable error has caused the 
update to fail.
+     */
+    public void update(RyaURI subject, EntityMutator mutator) throws 
EntityStorageException {
+        requireNonNull(subject);
+        requireNonNull(mutator);
+
+        // Fetch the current state of the Entity.
+        boolean completed = false;
+        while(!completed) {
+            try {
+                final Optional<Entity> old = storage.get(subject);
+                final Optional<Entity> updated = mutator.apply(old);
+
+                final boolean doWork = updated.isPresent();
+                if(doWork) {
+                    if(!old.isPresent()) {
+                        storage.create(updated.get());
+                    } else {
+                        storage.update(old.get(), updated.get());
+                    }
+                }
+                completed = true;
+            } catch(final EntityAlreadyExistsException | StaleUpdateException 
e) {
+                // These are recoverable exceptions. Try again.
+            } catch(final RuntimeException e) {
+                throw new EntityStorageException("Failed to update Entity with 
Subject '" + subject.getData() + "'.", e);
+            }
+        }
+    }
+
+    /**
+     * Implementations of this interface are used to update the state of an
+     * {@link Entity} in unison with a {@link EntityUpdater}.
+     * </p>
+     * This table describes what the updater will do depending on if an Entity
+     * exists and if an updated Entity is returned.
+     * </p>
+     * <table border="1px">
+     *     <tr><th>Entity Provided</th><th>Update 
Returned</th><th>Effect</th></tr>
+     *     <tr>
+     *         <td>true</td>
+     *         <td>true</td>
+     *         <td>The old Entity will be updated using the returned 
state.</td>
+     *     </tr>
+     *     <tr>
+     *         <td>true</td>
+     *         <td>false</td>
+     *         <td>No work is performed.</td>
+     *     </tr>
+     *     <tr>
+     *         <td>false</td>
+     *         <td>true</td>
+     *         <td>A new Entity will be created using the returned state.</td>
+     *     </tr>
+     *     <tr>
+     *         <td>false</td>
+     *         <td>false</td>
+     *         <td>No work is performed.</td>
+     *     </tr>
+     * </table>
+     */
+    public interface EntityMutator extends Function<Optional<Entity>, 
Optional<Entity>> { }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/c2a09dec/extras/indexing/src/main/java/mvm/rya/indexing/entity/update/mongo/MongoEntityIndexer.java
----------------------------------------------------------------------
diff --git 
a/extras/indexing/src/main/java/mvm/rya/indexing/entity/update/mongo/MongoEntityIndexer.java
 
b/extras/indexing/src/main/java/mvm/rya/indexing/entity/update/mongo/MongoEntityIndexer.java
new file mode 100644
index 0000000..94550ac
--- /dev/null
+++ 
b/extras/indexing/src/main/java/mvm/rya/indexing/entity/update/mongo/MongoEntityIndexer.java
@@ -0,0 +1,55 @@
+/**
+ * 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.
+ */
+package mvm.rya.indexing.entity.update.mongo;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
+import org.apache.hadoop.conf.Configuration;
+
+import com.mongodb.MongoClient;
+
+import mvm.rya.indexing.entity.storage.EntityStorage;
+import mvm.rya.indexing.entity.storage.TypeStorage;
+import mvm.rya.indexing.entity.storage.mongo.MongoEntityStorage;
+import mvm.rya.indexing.entity.storage.mongo.MongoTypeStorage;
+import mvm.rya.indexing.entity.update.BaseEntityIndexer;
+import mvm.rya.indexing.entity.update.EntityIndexer;
+import mvm.rya.mongodb.MongoConnectorFactory;
+import mvm.rya.mongodb.MongoDBRdfConfiguration;
+
+/**
+ * A Mongo DB implementation of {@link EntityIndexer}.
+ */
+@ParametersAreNonnullByDefault
+public class MongoEntityIndexer extends BaseEntityIndexer {
+
+    @Override
+    public EntityStorage getEntityStorage(Configuration conf) {
+        final MongoClient mongoClient = 
MongoConnectorFactory.getMongoClient(conf);
+        final String ryaInstanceName = new 
MongoDBRdfConfiguration(conf).getMongoDBName();
+        return new MongoEntityStorage(mongoClient, ryaInstanceName);
+    }
+
+    @Override
+    public TypeStorage getTypeStorage(Configuration conf) {
+        final MongoClient mongoClient = 
MongoConnectorFactory.getMongoClient(conf);
+        final String ryaInstanceName = new 
MongoDBRdfConfiguration(conf).getMongoDBName();
+        return new MongoTypeStorage(mongoClient, ryaInstanceName);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/c2a09dec/extras/indexing/src/test/java/mvm/rya/indexing/entity/query/EntityQueryNodeTest.java
----------------------------------------------------------------------
diff --git 
a/extras/indexing/src/test/java/mvm/rya/indexing/entity/query/EntityQueryNodeTest.java
 
b/extras/indexing/src/test/java/mvm/rya/indexing/entity/query/EntityQueryNodeTest.java
new file mode 100644
index 0000000..ab263e0
--- /dev/null
+++ 
b/extras/indexing/src/test/java/mvm/rya/indexing/entity/query/EntityQueryNodeTest.java
@@ -0,0 +1,194 @@
+/**
+ * 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.
+ */
+package mvm.rya.indexing.entity.query;
+
+import static org.mockito.Mockito.mock;
+
+import java.util.List;
+
+import org.junit.Test;
+import org.openrdf.model.vocabulary.RDF;
+import org.openrdf.query.MalformedQueryException;
+import org.openrdf.query.algebra.StatementPattern;
+import org.openrdf.query.algebra.helpers.StatementPatternCollector;
+import org.openrdf.query.parser.sparql.SPARQLParser;
+
+import com.google.common.collect.ImmutableSet;
+
+import mvm.rya.api.domain.RyaURI;
+import mvm.rya.indexing.entity.model.Type;
+import mvm.rya.indexing.entity.storage.EntityStorage;
+
+/**
+ * Unit tests the methods of {@link EntityQueryNode}.
+ */
+public class EntityQueryNodeTest {
+
+    private static final Type PERSON_TYPE =
+            new Type(new RyaURI("urn:person"),
+                ImmutableSet.<RyaURI>builder()
+                    .add(new RyaURI("urn:name"))
+                    .add(new RyaURI("urn:age"))
+                    .add(new RyaURI("urn:eye"))
+                    .build());
+
+    private static final Type EMPLOYEE_TYPE =
+            new Type(new RyaURI("urn:employee"),
+                ImmutableSet.<RyaURI>builder()
+                    .add(new RyaURI("urn:name"))
+                    .add(new RyaURI("urn:hoursPerWeek"))
+                    .build());
+
+    @Test(expected = IllegalStateException.class)
+    public void constructor_differentSubjects() throws Exception {
+        // A pattern that has two different subjects.
+        final List<StatementPattern> patterns = getSPs(
+                "SELECT * WHERE { " +
+                    "<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+
+                    "<urn:SSN:111-11-1111> <urn:age> ?age . " +
+                    "<urn:SSN:111-11-1111> <urn:eye> ?eye . " +
+                    "<urn:SSN:111-11-1111> <urn:name> ?name . " +
+                    "<urn:SSN:222-22-2222> <urn:age> ?age . " +
+                    "<urn:SSN:222-22-2222> <urn:eye> ?eye . " +
+                    "<urn:SSN:222-22-2222> <urn:name> ?name . " +
+                "}");
+
+
+        // This will fail.
+        new EntityQueryNode(PERSON_TYPE, patterns, mock(EntityStorage.class));
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void constructor_variablePredicate() throws Exception {
+        // A pattern that has a variable for its predicate.
+        final List<StatementPattern> patterns = getSPs(
+                "SELECT * WHERE { " +
+                    "?subject <" + RDF.TYPE + "> <urn:person> ."+
+                    "?subject ?variableProperty ?value . " +
+                    "?subject <urn:eye> ?eye . " +
+                    "?subject <urn:name> ?name . " +
+                "}");
+
+
+        // This will fail.
+        new EntityQueryNode(PERSON_TYPE, patterns, mock(EntityStorage.class));
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void constructor_predicateNotPartOfType() throws Exception {
+        // A pattern that does uses a predicate that is not part of the type.
+        final List<StatementPattern> patterns = getSPs(
+                "SELECT * WHERE { " +
+                    "?subject <" + RDF.TYPE + "> <urn:person> ."+
+                    "?subject <urn:age> ?age . " +
+                    "?subject <urn:eye> ?eye . " +
+                    "?subject <urn:name> ?name . " +
+                    "?subject <urn:notPartOfType> ?value . " +
+                "}");
+
+        // This will fail.
+        new EntityQueryNode(PERSON_TYPE, patterns, mock(EntityStorage.class));
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void constructor_typeMissing() throws Exception {
+        // A pattern that does uses a predicate that is not part of the type.
+        final List<StatementPattern> patterns = getSPs(
+                "SELECT * WHERE { " +
+                    "?subject <urn:age> ?age . " +
+                    "?subject <urn:eye> ?eye . " +
+                    "?subject <urn:name> ?name . " +
+                "}");
+
+        // This will fail.
+        new EntityQueryNode(PERSON_TYPE, patterns, mock(EntityStorage.class));
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void constructor_wrongType() throws Exception {
+        // A pattern that does uses a predicate that is not part of the type.
+        final List<StatementPattern> patterns = getSPs(
+                "SELECT * WHERE { " +
+                    "?subject <" + RDF.TYPE + "> <urn:person> ."+
+                    "?subject <urn:age> ?age . " +
+                    "?subject <urn:eye> ?eye . " +
+                    "?subject <urn:name> ?name . " +
+                "}");
+
+        // This will fail.
+        new EntityQueryNode(EMPLOYEE_TYPE, patterns, 
mock(EntityStorage.class));
+    }
+
+    // Happy path test.
+
+    // TODO test for all of the types of preconditions
+    //      test when a binding set can join
+    //      test when a binding set does not join
+    //      test when there are constants that are part of the query
+    //      test when there are variables that are part of the query.
+
+    @Test
+    public void evaluate_constantSubject() throws Exception {
+        // A set of patterns that match a sepecific Entity subject.
+        final List<StatementPattern> patterns = getSPs(
+                "SELECT * WHERE { " +
+                    "<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+
+                    "<urn:SSN:111-11-1111> <urn:age> ?age . " +
+                    "<urn:SSN:111-11-1111> <urn:eye> ?eye . " +
+                    "<urn:SSN:111-11-1111> <urn:name> ?name . " +
+                "}");
+
+        new EntityQueryNode(PERSON_TYPE, patterns, mock(EntityStorage.class));
+
+
+        // TODO implement
+    }
+
+    @Test
+    public void evaluate_variableSubject() throws Exception {
+        // A set of patterns that matches a variable Entity subject.
+        final List<StatementPattern> patterns = getSPs(
+                "SELECT * WHERE { " +
+                    "?subject <" + RDF.TYPE + "> <urn:person> ."+
+                    "?subject <urn:age> ?age . " +
+                    "?subject <urn:eye> ?eye . " +
+                    "?subject <urn:name> ?name . " +
+                "}");
+
+        new EntityQueryNode(PERSON_TYPE, patterns, mock(EntityStorage.class));
+
+
+        // TODO implement
+    }
+
+
+
+    /**
+     * TODO doc
+     *
+     * @param sparql
+     * @return
+     * @throws MalformedQueryException
+     */
+    private static List<StatementPattern> getSPs(String sparql) throws 
MalformedQueryException {
+        final StatementPatternCollector spCollector = new 
StatementPatternCollector();
+        new SPARQLParser().parseQuery(sparql, 
null).getTupleExpr().visit(spCollector);
+        return spCollector.getStatementPatterns();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/c2a09dec/extras/indexing/src/test/java/mvm/rya/indexing/entity/storage/mongo/EntityDocumentConverterTest.java
----------------------------------------------------------------------
diff --git 
a/extras/indexing/src/test/java/mvm/rya/indexing/entity/storage/mongo/EntityDocumentConverterTest.java
 
b/extras/indexing/src/test/java/mvm/rya/indexing/entity/storage/mongo/EntityDocumentConverterTest.java
new file mode 100644
index 0000000..bbd3f06
--- /dev/null
+++ 
b/extras/indexing/src/test/java/mvm/rya/indexing/entity/storage/mongo/EntityDocumentConverterTest.java
@@ -0,0 +1,60 @@
+/**
+ * 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.
+ */
+package mvm.rya.indexing.entity.storage.mongo;
+
+import static org.junit.Assert.assertEquals;
+
+import org.bson.Document;
+import org.junit.Test;
+import org.openrdf.model.vocabulary.XMLSchema;
+
+import mvm.rya.api.domain.RyaType;
+import mvm.rya.api.domain.RyaURI;
+import mvm.rya.indexing.entity.model.Entity;
+import mvm.rya.indexing.entity.model.Property;
+import 
mvm.rya.indexing.entity.storage.mongo.DocumentConverter.DocumentConverterException;
+
+/**
+ * Tests the methods of {@link EntityDocumentConverter}.
+ */
+public class EntityDocumentConverterTest {
+
+    @Test
+    public void to_and_from_document() throws DocumentConverterException {
+        // Convert an Entity into a Document.
+        final Entity entity = Entity.builder()
+                .setSubject(new RyaURI("urn:alice"))
+                // Add some explicily typed properties.
+                .setExplicitType(new RyaURI("urn:person"))
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:age"), new RyaType(XMLSchema.INT, "30")))
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:eye"), new RyaType("blue")))
+                // Add some implicitly typed properties.
+                .setProperty(new RyaURI("urn:employee"), new Property(new 
RyaURI("urn:hours"), new RyaType(XMLSchema.INT, "40")))
+                .setProperty(new RyaURI("urn:employee"), new Property(new 
RyaURI("urn:employer"), new RyaType("Burger Joint")))
+                .build();
+
+        final Document document = new 
EntityDocumentConverter().toDocument(entity);
+
+        // Convert the Document back into an Entity.
+        final Entity converted = new 
EntityDocumentConverter().fromDocument(document);
+
+        // Ensure the original matches the round trip converted Entity.
+        assertEquals(entity, converted);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/c2a09dec/extras/indexing/src/test/java/mvm/rya/indexing/entity/storage/mongo/MongoEntityStorageIT.java
----------------------------------------------------------------------
diff --git 
a/extras/indexing/src/test/java/mvm/rya/indexing/entity/storage/mongo/MongoEntityStorageIT.java
 
b/extras/indexing/src/test/java/mvm/rya/indexing/entity/storage/mongo/MongoEntityStorageIT.java
new file mode 100644
index 0000000..cc821c3
--- /dev/null
+++ 
b/extras/indexing/src/test/java/mvm/rya/indexing/entity/storage/mongo/MongoEntityStorageIT.java
@@ -0,0 +1,391 @@
+/**
+ * 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.
+ */
+package mvm.rya.indexing.entity.storage.mongo;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashSet;
+import java.util.Optional;
+import java.util.Set;
+
+import org.junit.Test;
+import org.openrdf.model.vocabulary.XMLSchema;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+
+import mvm.rya.api.domain.RyaType;
+import mvm.rya.api.domain.RyaURI;
+import mvm.rya.indexing.entity.model.Entity;
+import mvm.rya.indexing.entity.model.Property;
+import mvm.rya.indexing.entity.model.Type;
+import mvm.rya.indexing.entity.model.TypedEntity;
+import mvm.rya.indexing.entity.storage.CloseableIterator;
+import mvm.rya.indexing.entity.storage.EntityStorage;
+import 
mvm.rya.indexing.entity.storage.EntityStorage.EntityAlreadyExistsException;
+import mvm.rya.indexing.entity.storage.EntityStorage.EntityStorageException;
+import mvm.rya.indexing.entity.storage.EntityStorage.StaleUpdateException;
+
+/**
+ * Integration tests the methods of {@link MongoEntityStorage}.
+ */
+public class MongoEntityStorageIT extends MongoITBase {
+
+    private static final String RYA_INSTANCE_NAME = "testInstance";
+
+    @Test
+    public void create_and_get() throws EntityStorageException {
+        // An Entity that will be stored.
+        final Entity entity = Entity.builder()
+                .setSubject(new RyaURI("urn:GTIN-14/00012345600012"))
+                .setExplicitType(new RyaURI("urn:icecream"))
+                .setProperty(new RyaURI("urn:icecream"), new Property(new 
RyaURI("urn:brand"), new RyaType(XMLSchema.STRING, "Awesome Icecream")))
+                .setProperty(new RyaURI("urn:icecream"), new Property(new 
RyaURI("urn:flavor"), new RyaType(XMLSchema.STRING, "Chocolate")))
+                .build();
+
+        // Create it.
+        final EntityStorage storage = new 
MongoEntityStorage(super.getMongoClient(), RYA_INSTANCE_NAME);
+        storage.create(entity);
+
+        // Get it.
+        final Optional<Entity> storedEntity = storage.get(new 
RyaURI("urn:GTIN-14/00012345600012"));
+
+        // Verify the correct value was returned.
+        assertEquals(entity, storedEntity.get());
+    }
+
+    @Test
+    public void can_not_create_with_same_subject() throws 
EntityStorageException {
+        // A Type that will be stored.
+        final Entity entity = Entity.builder()
+                .setSubject(new RyaURI("urn:GTIN-14/00012345600012"))
+                .setExplicitType(new RyaURI("urn:icecream"))
+                .setProperty(new RyaURI("urn:icecream"), new Property(new 
RyaURI("urn:brand"), new RyaType(XMLSchema.STRING, "Awesome Icecream")))
+                .setProperty(new RyaURI("urn:icecream"), new Property(new 
RyaURI("urn:flavor"), new RyaType(XMLSchema.STRING, "Chocolate")))
+                .build();
+
+        // Create it.
+        final EntityStorage storage = new 
MongoEntityStorage(super.getMongoClient(), RYA_INSTANCE_NAME);
+        storage.create(entity);
+
+        // Try to create it again. This will fail.
+        boolean failed = false;
+        try {
+            storage.create(entity);
+        } catch(final EntityAlreadyExistsException e) {
+            failed = true;
+        }
+        assertTrue(failed);
+    }
+
+    @Test
+    public void get_noneExisting() throws EntityStorageException {
+        // Get a Type that hasn't been created.
+        final EntityStorage storage = new 
MongoEntityStorage(super.getMongoClient(), RYA_INSTANCE_NAME);
+        final Optional<Entity> storedEntity = storage.get(new 
RyaURI("urn:GTIN-14/00012345600012"));
+
+        // Verify nothing was returned.
+        assertFalse(storedEntity.isPresent());
+    }
+
+    @Test
+    public void delete() throws EntityStorageException {
+        // An Entity that will be stored.
+        final Entity entity = Entity.builder()
+                .setSubject(new RyaURI("urn:GTIN-14/00012345600012"))
+                .setExplicitType(new RyaURI("urn:icecream"))
+                .setProperty(new RyaURI("urn:icecream"), new Property(new 
RyaURI("urn:brand"), new RyaType(XMLSchema.STRING, "Awesome Icecream")))
+                .setProperty(new RyaURI("urn:icecream"), new Property(new 
RyaURI("urn:flavor"), new RyaType(XMLSchema.STRING, "Chocolate")))
+                .build();
+
+        // Create it.
+        final EntityStorage storage = new 
MongoEntityStorage(super.getMongoClient(), RYA_INSTANCE_NAME);
+        storage.create(entity);
+
+        // Delete it.
+        final boolean deleted = storage.delete( new 
RyaURI("urn:GTIN-14/00012345600012") );
+
+        // Verify a document was deleted.
+        assertTrue( deleted );
+    }
+
+    @Test
+    public void delete_nonExisting() throws EntityStorageException {
+        // Delete an Entity that has not been created.
+        final EntityStorage storage = new 
MongoEntityStorage(super.getMongoClient(), RYA_INSTANCE_NAME);
+        final boolean deleted = storage.delete( new 
RyaURI("urn:GTIN-14/00012345600012") );
+
+        // Verify no document was deleted.
+        assertFalse( deleted );
+    }
+
+    @Test
+    public void search_byDataType() throws Exception {
+        final EntityStorage storage = new 
MongoEntityStorage(super.getMongoClient(), RYA_INSTANCE_NAME);
+
+        // The Type we will search by.
+        final Type icecreamType = new Type(new RyaURI("urn:icecream"),
+                ImmutableSet.<RyaURI>builder()
+                    .add(new RyaURI("urn:brand"))
+                    .add(new RyaURI("urn:flavor"))
+                    .add(new RyaURI("urn:cost"))
+                    .build());
+
+        // Some Person typed entities.
+        final Entity alice = Entity.builder()
+                .setSubject( new RyaURI("urn:SSN/111-11-1111") )
+                .setExplicitType(new RyaURI("urn:person"))
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:name"), new RyaType(XMLSchema.STRING, "Alice")))
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:age"), new RyaType(XMLSchema.INT, "30")))
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:eye"), new RyaType(XMLSchema.STRING, "blue")))
+                .build();
+
+        final Entity bob = Entity.builder()
+                .setSubject( new RyaURI("urn:SSN/222-22-2222") )
+                .setExplicitType(new RyaURI("urn:person"))
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:name"), new RyaType(XMLSchema.STRING, "Bob")))
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:age"), new RyaType(XMLSchema.INT, "57")))
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:eye"), new RyaType(XMLSchema.STRING, "blue")))
+                .build();
+
+        // Some Icecream typed objects.
+        final Entity chocolateIcecream = Entity.builder()
+                .setSubject(new RyaURI("urn:GTIN-14/00012345600012"))
+                .setExplicitType(new RyaURI("urn:icecream"))
+                .setProperty(new RyaURI("urn:icecream"), new Property(new 
RyaURI("urn:brand"), new RyaType(XMLSchema.STRING, "Awesome Icecream")))
+                .setProperty(new RyaURI("urn:icecream"), new Property(new 
RyaURI("urn:flavor"), new RyaType(XMLSchema.STRING, "Chocolate")))
+                .build();
+
+        final Entity vanillaIcecream = Entity.builder()
+                .setSubject( new RyaURI("urn:GTIN-14/22356325213432") )
+                .setExplicitType(new RyaURI("urn:icecream"))
+                .setProperty(new RyaURI("urn:icecream"), new Property(new 
RyaURI("urn:brand"), new RyaType(XMLSchema.STRING, "Awesome Icecream")))
+                .setProperty(new RyaURI("urn:icecream"), new Property(new 
RyaURI("urn:flavor"), new RyaType(XMLSchema.STRING, "Vanilla")))
+                .build();
+
+
+        final Entity strawberryIcecream = Entity.builder()
+                .setSubject( new RyaURI("urn:GTIN-14/77544325436721") )
+                .setProperty(new RyaURI("urn:icecream"), new Property(new 
RyaURI("urn:brand"), new RyaType(XMLSchema.STRING, "Awesome Icecream")))
+                .setProperty(new RyaURI("urn:icecream"), new Property(new 
RyaURI("urn:flavor"), new RyaType(XMLSchema.STRING, "Strawberry")))
+                .build();
+
+        // Create the objects in the storage.
+        storage.create(alice);
+        storage.create(bob);
+        storage.create(chocolateIcecream);
+        storage.create(vanillaIcecream);
+        storage.create(strawberryIcecream);
+
+        // Search for all icecreams.
+        final Set<TypedEntity> objects = new HashSet<>();
+        try(final CloseableIterator<TypedEntity> it = 
storage.search(icecreamType, new HashSet<>())) {
+            while(it.hasNext()) {
+                objects.add(it.next());
+            }
+        }
+
+        // Verify the expected results were returned.
+        final Set<TypedEntity> expected = Sets.newHashSet(
+                chocolateIcecream.makeTypedEntity(new 
RyaURI("urn:icecream")).get(),
+                vanillaIcecream.makeTypedEntity(new 
RyaURI("urn:icecream")).get());
+        assertEquals(expected, objects);
+    }
+
+    @Test
+    public void search_byFields() throws Exception {
+        final EntityStorage storage = new 
MongoEntityStorage(super.getMongoClient(), RYA_INSTANCE_NAME);
+
+        // A Type that defines a Person.
+        final Type personType = new Type(new RyaURI("urn:person"),
+                ImmutableSet.<RyaURI>builder()
+                    .add(new RyaURI("urn:name"))
+                    .add(new RyaURI("urn:age"))
+                    .add(new RyaURI("urn:eye"))
+                    .build());
+
+        // Some Person typed objects.
+        final Entity alice = Entity.builder()
+                .setSubject( new RyaURI("urn:SSN/111-11-1111") )
+                .setExplicitType(new RyaURI("urn:person"))
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:name"), new RyaType(XMLSchema.STRING, "Alice")))
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:age"), new RyaType(XMLSchema.INT, "30")))
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:eye"), new RyaType(XMLSchema.STRING, "blue")))
+                .build();
+
+        final Entity bob = Entity.builder()
+                .setSubject( new RyaURI("urn:SSN/222-22-2222") )
+                .setExplicitType(new RyaURI("urn:person"))
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:name"), new RyaType(XMLSchema.STRING, "Bob")))
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:age"), new RyaType(XMLSchema.INT, "57")))
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:eye"), new RyaType(XMLSchema.STRING, "blue")))
+                .build();
+
+
+        final Entity charlie = Entity.builder()
+                .setSubject( new RyaURI("urn:SSN/333-33-3333") )
+                .setExplicitType( new RyaURI("urn:person") )
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:name"), new RyaType(XMLSchema.STRING, "Charlie")))
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:age"), new RyaType(XMLSchema.INT, "30")))
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:eye"), new RyaType(XMLSchema.STRING, "blue")))
+                .build();
+
+        final Entity david = Entity.builder()
+                .setSubject( new RyaURI("urn:SSN/444-44-4444") )
+                .setExplicitType( new RyaURI("urn:person") )
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:name"), new RyaType(XMLSchema.STRING, "David")))
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:age"), new RyaType(XMLSchema.INT, "30")))
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:eye"), new RyaType(XMLSchema.STRING, "brown")))
+                .build();
+
+        final Entity eve = Entity.builder()
+                .setSubject( new RyaURI("urn:SSN/555-55-5555") )
+                .setExplicitType( new RyaURI("urn:person") )
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:name"), new RyaType(XMLSchema.STRING, "Eve")))
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:age"), new RyaType(XMLSchema.INT, "30")))
+                .build();
+
+        final Entity frank = Entity.builder()
+                .setSubject( new RyaURI("urn:SSN/666-66-6666") )
+                .setExplicitType( new RyaURI("urn:person") )
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:name"), new RyaType(XMLSchema.STRING, "Frank")))
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:eye"), new RyaType(XMLSchema.STRING, "blue")))
+                .setProperty(new RyaURI("urn:someOtherType"), new Property(new 
RyaURI("urn:age"), new RyaType(XMLSchema.INT, "30")))
+                .build();
+
+        final Entity george = Entity.builder()
+                .setSubject( new RyaURI("urn:SSN/777-77-7777") )
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:name"), new RyaType(XMLSchema.STRING, "George")))
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:age"), new RyaType(XMLSchema.INT, "30")))
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:eye"), new RyaType(XMLSchema.STRING, "blue")))
+                .build();
+
+        // Create the objects in the storage.
+        storage.create(alice);
+        storage.create(bob);
+        storage.create(charlie);
+        storage.create(david);
+        storage.create(eve);
+        storage.create(frank);
+        storage.create(george);
+
+        // Search for all people who are 30 and have blue eyes.
+        final Set<TypedEntity> objects = new HashSet<>();
+
+        final Set<Property> searchValues = Sets.newHashSet(
+                new Property(new RyaURI("urn:eye"), new 
RyaType(XMLSchema.STRING, "blue")),
+                new Property(new RyaURI("urn:age"), new RyaType(XMLSchema.INT, 
"30")));
+
+        try(final CloseableIterator<TypedEntity> it = 
storage.search(personType, searchValues)) {
+            while(it.hasNext()) {
+                objects.add(it.next());
+            }
+        }
+
+        // Verify the expected results were returned.
+        assertEquals(2, objects.size());
+        assertTrue(objects.contains(alice.makeTypedEntity(new 
RyaURI("urn:person")).get()));
+        assertTrue(objects.contains(charlie.makeTypedEntity(new 
RyaURI("urn:person")).get()));
+    }
+
+    @Test
+    public void update() throws EntityStorageException {
+        final EntityStorage storage = new 
MongoEntityStorage(super.getMongoClient(), RYA_INSTANCE_NAME);
+
+        // Store Alice in the repository.
+        final Entity alice = Entity.builder()
+                .setSubject( new RyaURI("urn:SSN/111-11-1111") )
+                .setExplicitType(new RyaURI("urn:person"))
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:name"), new RyaType(XMLSchema.STRING, "Alice")))
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:age"), new RyaType(XMLSchema.INT, "30")))
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:eye"), new RyaType(XMLSchema.STRING, "blue")))
+                .build();
+
+        storage.create(alice);
+
+        // Show Alice was stored.
+        Optional<Entity> latest = storage.get(new 
RyaURI("urn:SSN/111-11-1111"));
+        assertEquals(alice, latest.get());
+
+        // Change Alice's eye color to brown.
+        final Entity updated = Entity.builder(alice)
+                .setVersion(latest.get().getVersion() + 1)
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:eye"), new RyaType(XMLSchema.STRING, "brown")))
+                .build();
+
+        storage.update(alice, updated);
+
+        // Fetch the Alice object and ensure it has the new value.
+        latest = storage.get(new RyaURI("urn:SSN/111-11-1111"));
+
+        assertEquals(updated, latest.get());
+    }
+
+    @Test(expected = StaleUpdateException.class)
+    public void update_stale() throws EntityStorageException {
+        final EntityStorage storage = new 
MongoEntityStorage(super.getMongoClient(), RYA_INSTANCE_NAME);
+
+        // Store Alice in the repository.
+        final Entity alice = Entity.builder()
+                .setSubject( new RyaURI("urn:SSN/111-11-1111") )
+                .setExplicitType(new RyaURI("urn:person"))
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:name"), new RyaType(XMLSchema.STRING, "Alice")))
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:age"), new RyaType(XMLSchema.INT, "30")))
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:eye"), new RyaType(XMLSchema.STRING, "blue")))
+                .build();
+
+        storage.create(alice);
+
+        // Show Alice was stored.
+        final Optional<Entity> latest = storage.get(new 
RyaURI("urn:SSN/111-11-1111"));
+        assertEquals(alice, latest.get());
+
+        // Create the wrong old state and try to change Alice's eye color to 
brown.
+        final Entity wrongOld = Entity.builder(alice)
+                .setVersion(500)
+                .build();
+
+        final Entity updated = Entity.builder(alice)
+                .setVersion(501)
+                .setProperty(new RyaURI("urn:person"), new Property(new 
RyaURI("urn:eye"), new RyaType(XMLSchema.STRING, "brown")))
+                .build();
+
+        storage.update(wrongOld, updated);
+    }
+
+    @Test(expected = EntityStorageException.class)
+    public void update_differentSubjects() throws StaleUpdateException, 
EntityStorageException {
+        // Two objects that do not have the same Subjects.
+        final Entity old = Entity.builder()
+                .setSubject( new RyaURI("urn:SSN/111-11-1111") )
+                .setExplicitType( new RyaURI("urn:person") )
+                .build();
+
+        final Entity updated = Entity.builder()
+                .setSubject( new RyaURI("urn:SSN/222-22-2222") )
+                .setExplicitType( new RyaURI("urn:person") )
+                .build();
+
+        // The update will fail.
+        final EntityStorage storage = new 
MongoEntityStorage(super.getMongoClient(), RYA_INSTANCE_NAME);
+        storage.update(old, updated);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/c2a09dec/extras/indexing/src/test/java/mvm/rya/indexing/entity/storage/mongo/MongoITBase.java
----------------------------------------------------------------------
diff --git 
a/extras/indexing/src/test/java/mvm/rya/indexing/entity/storage/mongo/MongoITBase.java
 
b/extras/indexing/src/test/java/mvm/rya/indexing/entity/storage/mongo/MongoITBase.java
new file mode 100644
index 0000000..760a816
--- /dev/null
+++ 
b/extras/indexing/src/test/java/mvm/rya/indexing/entity/storage/mongo/MongoITBase.java
@@ -0,0 +1,81 @@
+/**
+ * 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.
+ */
+package mvm.rya.indexing.entity.storage.mongo;
+
+import java.net.UnknownHostException;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.hadoop.conf.Configuration;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+
+import com.mongodb.MongoClient;
+import com.mongodb.MongoException;
+
+import mvm.rya.mongodb.MongoConnectorFactory;
+import mvm.rya.mongodb.MongoDBRdfConfiguration;
+
+/**
+ * A base class that may be used when implementing Mongo DB integration tests 
that
+ * use the JUnit framework.
+ */
+public class MongoITBase {
+
+    private MongoClient mongoClient = null;
+    private Set<String> originalDbNames = null;
+
+    @Before
+    public void setupTest() throws UnknownHostException, MongoException {
+        final MongoDBRdfConfiguration conf = new MongoDBRdfConfiguration( new 
Configuration() );
+        conf.setUseTestMongo(true);
+        conf.setMongoDBName("testDB");
+
+        mongoClient = MongoConnectorFactory.getMongoClient(conf);
+
+        // Store the names of the DBs that are present before running the test.
+        originalDbNames = new HashSet<>();
+        for(final String name : mongoClient.listDatabaseNames()) {
+            originalDbNames.add(name);
+        }
+    }
+
+    @After
+    public void cleanupTest() {
+        // Remove any DBs that were created by the test.
+        for(final String dbName : mongoClient.listDatabaseNames()) {
+            if(!originalDbNames.contains(dbName)) {
+                mongoClient.dropDatabase(dbName);
+            }
+        }
+    }
+
+    @AfterClass
+    public static void shutdown() {
+        MongoConnectorFactory.shutdown();
+    }
+
+    /**
+     * @return A {@link MongoClient} that is connected to the embedded 
instance of Mongo DB.
+     */
+    public MongoClient getMongoClient() {
+        return mongoClient;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/c2a09dec/extras/indexing/src/test/java/mvm/rya/indexing/entity/storage/mongo/MongoTypeStorageIT.java
----------------------------------------------------------------------
diff --git 
a/extras/indexing/src/test/java/mvm/rya/indexing/entity/storage/mongo/MongoTypeStorageIT.java
 
b/extras/indexing/src/test/java/mvm/rya/indexing/entity/storage/mongo/MongoTypeStorageIT.java
new file mode 100644
index 0000000..6809247
--- /dev/null
+++ 
b/extras/indexing/src/test/java/mvm/rya/indexing/entity/storage/mongo/MongoTypeStorageIT.java
@@ -0,0 +1,174 @@
+/**
+ * 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.
+ */
+package mvm.rya.indexing.entity.storage.mongo;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.junit.Test;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+
+import mvm.rya.api.domain.RyaURI;
+import mvm.rya.indexing.entity.model.Type;
+import mvm.rya.indexing.entity.storage.CloseableIterator;
+import mvm.rya.indexing.entity.storage.TypeStorage;
+import mvm.rya.indexing.entity.storage.TypeStorage.TypeStorageException;
+
+/**
+ * Integration tests the methods of {@link MongoTypeStorage}.
+ */
+public class MongoTypeStorageIT extends MongoITBase {
+
+    private static final String RYA_INSTANCE_NAME = "testInstance";
+
+    @Test
+    public void create_and_get() throws TypeStorageException {
+        // A Type that will be stored.
+        final Type type = new Type(new RyaURI("urn:icecream"),
+                ImmutableSet.<RyaURI>builder()
+                    .add(new RyaURI("urn:brand"))
+                    .add(new RyaURI("urn:flavor"))
+                    .add(new RyaURI("urn:cost"))
+                    .build());
+
+        // Create it.
+        final TypeStorage storage = new 
MongoTypeStorage(super.getMongoClient(), RYA_INSTANCE_NAME);
+        storage.create(type);
+
+        // Get it.
+        final Optional<Type> storedType = storage.get(new 
RyaURI("urn:icecream"));
+
+        // Verify the correct value was returned.
+        assertEquals(type, storedType.get());
+    }
+
+    @Test
+    public void can_not_create_with_same_id() throws TypeStorageException {
+        // A Type that will be stored.
+        final Type type = new Type(new RyaURI("urn:icecream"),
+                ImmutableSet.<RyaURI>builder()
+                    .add(new RyaURI("urn:brand"))
+                    .add(new RyaURI("urn:flavor"))
+                    .add(new RyaURI("urn:cost"))
+                    .build());
+
+        // Create it.
+        final TypeStorage storage = new 
MongoTypeStorage(super.getMongoClient(), RYA_INSTANCE_NAME);
+        storage.create(type);
+
+        // Try to create it again. This will fail.
+        boolean failed = false;
+        try {
+            storage.create(type);
+        } catch(final TypeStorageException e) {
+            failed = true;
+        }
+        assertTrue(failed);
+    }
+
+    @Test
+    public void get_nonexisting() throws TypeStorageException {
+        // Get a Type that hasn't been created.
+        final TypeStorage storage = new 
MongoTypeStorage(super.getMongoClient(), RYA_INSTANCE_NAME);
+        final Optional<Type> storedType = storage.get(new 
RyaURI("urn:icecream"));
+
+        // Verify nothing was returned.
+        assertFalse(storedType.isPresent());
+    }
+
+    @Test
+    public void delete() throws TypeStorageException {
+        // An Type that will be stored.
+        final Type type = new Type(new RyaURI("urn:icecream"),
+                ImmutableSet.<RyaURI>builder()
+                    .add(new RyaURI("urn:brand"))
+                    .add(new RyaURI("urn:flavor"))
+                    .add(new RyaURI("urn:cost"))
+                    .build());
+
+        // Create it.
+        final TypeStorage storage = new 
MongoTypeStorage(super.getMongoClient(), RYA_INSTANCE_NAME);
+        storage.create(type);
+
+        // Delete it.
+        final boolean deleted = storage.delete( new RyaURI("urn:icecream") );
+
+        // Verify a document was deleted.
+        assertTrue( deleted );
+    }
+
+    @Test
+    public void delete_nonexisting() throws TypeStorageException {
+        // Delete an Type that has not been created.
+        final TypeStorage storage = new 
MongoTypeStorage(super.getMongoClient(), RYA_INSTANCE_NAME);
+        final boolean deleted = storage.delete( new RyaURI("urn:icecream") );
+
+        // Verify no document was deleted.
+        assertFalse( deleted );
+    }
+
+    @Test
+    public void search() throws Exception {
+        // Add some Types to the storage.
+        final Type cat = new Type(new RyaURI("urn:cat"),
+                ImmutableSet.<RyaURI>builder()
+                    .add(new RyaURI("urn:numLegs"))
+                    .add(new RyaURI("urn:eye"))
+                    .add(new RyaURI("urn:species"))
+                    .build());
+
+        final Type dog = new Type(new RyaURI("urn:dog"),
+                ImmutableSet.<RyaURI>builder()
+                    .add(new RyaURI("urn:numLegs"))
+                    .add(new RyaURI("urn:eye"))
+                    .add(new RyaURI("urn:species"))
+                    .build());
+
+        final Type icecream = new Type(new RyaURI("urn:icecream"),
+                ImmutableSet.<RyaURI>builder()
+                    .add(new RyaURI("urn:brand"))
+                    .add(new RyaURI("urn:flavor"))
+                    .add(new RyaURI("urn:cost"))
+                    .build());
+
+        final TypeStorage storage = new 
MongoTypeStorage(super.getMongoClient(), RYA_INSTANCE_NAME);
+        storage.create(cat);
+        storage.create(dog);
+        storage.create(icecream);
+
+        // Search for all Types that have the 'urn:eye' property.
+        final CloseableIterator<Type> typeIt = storage.search(new 
RyaURI("urn:eye"));
+
+        final Set<Type> types = new HashSet<>();
+        while(typeIt.hasNext()) {
+            types.add( typeIt.next() );
+        }
+
+        // Verify the correct types were returned.
+        final Set<Type> expected = Sets.newHashSet(cat, dog);
+        assertEquals(expected, types);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/c2a09dec/extras/indexing/src/test/java/mvm/rya/indexing/entity/storage/mongo/RyaTypeDocumentConverterTest.java
----------------------------------------------------------------------
diff --git 
a/extras/indexing/src/test/java/mvm/rya/indexing/entity/storage/mongo/RyaTypeDocumentConverterTest.java
 
b/extras/indexing/src/test/java/mvm/rya/indexing/entity/storage/mongo/RyaTypeDocumentConverterTest.java
new file mode 100644
index 0000000..0626009
--- /dev/null
+++ 
b/extras/indexing/src/test/java/mvm/rya/indexing/entity/storage/mongo/RyaTypeDocumentConverterTest.java
@@ -0,0 +1,82 @@
+/**
+ * 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.
+ */
+package mvm.rya.indexing.entity.storage.mongo;
+
+import static org.junit.Assert.assertEquals;
+
+import org.bson.Document;
+import org.junit.Test;
+import org.openrdf.model.impl.ValueFactoryImpl;
+import org.openrdf.model.vocabulary.XMLSchema;
+
+import mvm.rya.api.domain.RyaType;
+import mvm.rya.api.resolver.RdfToRyaConversions;
+import 
mvm.rya.indexing.entity.storage.mongo.DocumentConverter.DocumentConverterException;
+
+/**
+ * Tests the methods of {@link RyaTypeDocumentConverter}.
+ */
+public class RyaTypeDocumentConverterTest {
+
+    @Test
+    public void toDocument() {
+        // Convert the RyaType into a Document.
+        final RyaType ryaType = RdfToRyaConversions.convertLiteral( new 
ValueFactoryImpl().createLiteral( 4.5 ) );
+        final Document document = new RyaTypeDocumentConverter().toDocument( 
ryaType );
+
+        // Show the document has the correct structure.
+        final Document expected = new Document()
+                .append(RyaTypeDocumentConverter.DATA_TYPE, 
XMLSchema.DOUBLE.toString())
+                .append(RyaTypeDocumentConverter.VALUE, "4.5");
+        assertEquals(expected, document);
+    }
+
+    @Test
+    public void fromDocument() throws DocumentConverterException {
+        // Convert a document into a RyaType
+        final Document document = new Document()
+                .append(RyaTypeDocumentConverter.DATA_TYPE, 
XMLSchema.DOUBLE.toString())
+                .append(RyaTypeDocumentConverter.VALUE, "4.5");
+        final RyaType ryaType = new RyaTypeDocumentConverter().fromDocument( 
document );
+
+        // Show the converted value has the expected structure.
+        final RyaType expected = RdfToRyaConversions.convertLiteral( new 
ValueFactoryImpl().createLiteral( 4.5 ) );
+        assertEquals(expected, ryaType);
+    }
+
+    @Test(expected = DocumentConverterException.class)
+    public void fromDocument_noDataType() throws DocumentConverterException {
+        // A document that does not have a data type.
+        final Document document = new Document()
+                .append(RyaTypeDocumentConverter.VALUE, "4.5");
+
+        // The conversion will fail.
+        new RyaTypeDocumentConverter().fromDocument(document);
+    }
+
+    @Test(expected = DocumentConverterException.class)
+    public void fromDocument_noValue() throws DocumentConverterException {
+        // A document that does not have a value.
+        final Document document = new Document()
+            .append(RyaTypeDocumentConverter.DATA_TYPE, 
XMLSchema.DOUBLE.toString());
+
+        // The conversion will fail.
+        new RyaTypeDocumentConverter().fromDocument(document);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/c2a09dec/extras/indexing/src/test/java/mvm/rya/indexing/entity/storage/mongo/TypeDocumentConverterTest.java
----------------------------------------------------------------------
diff --git 
a/extras/indexing/src/test/java/mvm/rya/indexing/entity/storage/mongo/TypeDocumentConverterTest.java
 
b/extras/indexing/src/test/java/mvm/rya/indexing/entity/storage/mongo/TypeDocumentConverterTest.java
new file mode 100644
index 0000000..8b5bc7f
--- /dev/null
+++ 
b/extras/indexing/src/test/java/mvm/rya/indexing/entity/storage/mongo/TypeDocumentConverterTest.java
@@ -0,0 +1,93 @@
+/**
+ * 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.
+ */
+package mvm.rya.indexing.entity.storage.mongo;
+
+import static org.junit.Assert.assertEquals;
+
+import org.bson.Document;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+
+import mvm.rya.api.domain.RyaURI;
+import mvm.rya.indexing.entity.model.Type;
+import 
mvm.rya.indexing.entity.storage.mongo.DocumentConverter.DocumentConverterException;
+
+/**
+ * Tests the methods of {@link TypeDocumentConverter}.
+ */
+public class TypeDocumentConverterTest {
+
+    @Test
+    public void toDocument() {
+        // Convert a Type into a Document.
+        final Type type = new Type(new RyaURI("urn:icecream"),
+                ImmutableSet.<RyaURI>builder()
+                    .add(new RyaURI("urn:brand"))
+                    .add(new RyaURI("urn:flavor"))
+                    .add(new RyaURI("urn:cost"))
+                    .build());
+        final Document document = new TypeDocumentConverter().toDocument(type);
+
+        // Show the document has the correct values.
+        final Document expected = new Document()
+                .append(TypeDocumentConverter.ID, "urn:icecream")
+                .append(TypeDocumentConverter.PROPERTY_NAMES, 
Lists.newArrayList("urn:brand", "urn:flavor", "urn:cost"));
+        assertEquals(expected, document);
+    }
+
+    @Test
+    public void fromDocument() throws DocumentConverterException {
+        // Convert a Document into a Type.
+        final Document document = new Document()
+                .append(TypeDocumentConverter.ID, "urn:icecream")
+                .append(TypeDocumentConverter.PROPERTY_NAMES, 
Lists.newArrayList("urn:brand", "urn:flavor", "urn:cost"));
+        final Type type = new TypeDocumentConverter().fromDocument(document);
+
+        // Show the converted value has the expected structure.
+        final Type expected = new Type(new RyaURI("urn:icecream"),
+                ImmutableSet.<RyaURI>builder()
+                    .add(new RyaURI("urn:brand"))
+                    .add(new RyaURI("urn:flavor"))
+                    .add(new RyaURI("urn:cost"))
+                    .build());
+        assertEquals(expected, type);
+    }
+
+    @Test(expected = DocumentConverterException.class)
+    public void fromDocument_noId() throws DocumentConverterException {
+        // A document that does not have a Data Type ID.
+        final Document document = new Document()
+                .append(TypeDocumentConverter.PROPERTY_NAMES, 
Lists.newArrayList("urn:brand", "urn:flavor", "urn:cost"));
+
+        // The conversion will fail.
+        new TypeDocumentConverter().fromDocument(document);
+    }
+
+    @Test(expected = DocumentConverterException.class)
+    public void fromDocument_noOptionalFieldNames() throws 
DocumentConverterException {
+        // A document that does not have an Optional Field Names.
+        final Document document = new Document()
+                .append(TypeDocumentConverter.ID, "urn:icecream");
+
+        // The conversion will fail.
+        new TypeDocumentConverter().fromDocument(document);
+    }
+}
\ No newline at end of file

Reply via email to