http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/07643eb7/extras/indexing/src/main/java/mvm/rya/indexing/entity/storage/mongo/MongoTypeStorage.java
----------------------------------------------------------------------
diff --git 
a/extras/indexing/src/main/java/mvm/rya/indexing/entity/storage/mongo/MongoTypeStorage.java
 
b/extras/indexing/src/main/java/mvm/rya/indexing/entity/storage/mongo/MongoTypeStorage.java
deleted file mode 100644
index dbeff56..0000000
--- 
a/extras/indexing/src/main/java/mvm/rya/indexing/entity/storage/mongo/MongoTypeStorage.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/**
- * 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.bson.conversions.Bson;
-
-import com.google.common.base.Optional;
-import com.mongodb.MongoClient;
-import com.mongodb.MongoException;
-import com.mongodb.client.MongoCursor;
-import com.mongodb.client.model.Filters;
-
-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.mongo.DocumentConverter.DocumentConverterException;
-
-/**
- * A Mongo DB implementation of {@link TypeStorage}.
- */
-@ParametersAreNonnullByDefault
-public class MongoTypeStorage implements TypeStorage {
-
-    private static final String COLLECTION_NAME = "entity-types";
-
-    private static final TypeDocumentConverter TYPE_CONVERTER = new 
TypeDocumentConverter();
-
-    /**
-     * A client connected to the Mongo instance that hosts the Rya instance.
-     */
-    private final MongoClient mongo;
-
-    /**
-     * The name of the Rya instance the {@link Type}s are for.
-     */
-    private final String ryaInstanceName;
-
-    /**
-     * Constructs an instance of {@link MongoTypeStorage}.
-     *
-     * @param mongo - A client connected to the Mongo instance that hosts the 
Rya instance. (not null)
-     * @param ryaInstanceName - The name of the Rya instance the {@link Type}s 
are for. (not null)
-     */
-    public MongoTypeStorage(MongoClient mongo, String ryaInstanceName) {
-        this.mongo = requireNonNull(mongo);
-        this.ryaInstanceName = requireNonNull(ryaInstanceName);
-    }
-
-    @Override
-    public void create(Type type) throws TypeStorageException {
-        requireNonNull(type);
-
-        try {
-            mongo.getDatabase(ryaInstanceName)
-                .getCollection(COLLECTION_NAME)
-                .insertOne(TYPE_CONVERTER.toDocument(type));
-
-        } catch(final MongoException e) {
-            throw new TypeStorageException("Failed to create Type with ID '" + 
type.getId().getData() + "'.", e);
-        }
-    }
-
-    @Override
-    public Optional<Type> get(RyaURI typeId) throws TypeStorageException {
-        requireNonNull(typeId);
-
-        try {
-            final Document document = mongo.getDatabase(ryaInstanceName)
-                .getCollection(COLLECTION_NAME)
-                .find( makeIdFilter(typeId) )
-                .first();
-
-            return document == null ?
-                    Optional.absent() :
-                    Optional.of( TYPE_CONVERTER.fromDocument(document) );
-
-        } catch(final MongoException | DocumentConverterException e) {
-            throw new TypeStorageException("Could not get the Type with ID '" 
+ typeId.getData() + "'.", e);
-        }
-    }
-
-    @Override
-    public CloseableIterator<Type> search(RyaURI propertyName) throws 
TypeStorageException {
-        requireNonNull(propertyName);
-
-        try {
-            // Create a Filter that finds Types who have the provided property 
names.
-            final Bson byPropertyName = 
Filters.eq(TypeDocumentConverter.PROPERTY_NAMES, propertyName.getData());
-
-            final MongoCursor<Document> cursor = 
mongo.getDatabase(ryaInstanceName)
-                .getCollection(COLLECTION_NAME)
-                .find( byPropertyName )
-                .iterator();
-
-            return new ConvertingCursor<Type>(document -> {
-                try {
-                    return TYPE_CONVERTER.fromDocument(document);
-                } catch (final Exception e) {
-                    throw new RuntimeException("Could not convert the Document 
'" + document + "' into a Type.", e);
-                }
-            }, cursor);
-
-        } catch(final MongoException e) {
-            throw new TypeStorageException("Could not fetch Types that include 
the property '" + propertyName.getData() + "'.", e);
-        }
-    }
-
-    @Override
-    public boolean delete(RyaURI typeId) throws TypeStorageException {
-        requireNonNull(typeId);
-
-        try {
-            final Document deleted = mongo.getDatabase(ryaInstanceName)
-                .getCollection(COLLECTION_NAME)
-                .findOneAndDelete( makeIdFilter(typeId) );
-
-            return deleted != null;
-
-        } catch(final MongoException e) {
-            throw new TypeStorageException("Could not delete the Type with ID 
'" + typeId.getData() + "'.", e);
-        }
-    }
-
-    private static Bson makeIdFilter(RyaURI typeId) {
-        return Filters.eq(TypeDocumentConverter.ID, typeId.getData());
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/07643eb7/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
deleted file mode 100644
index ab6148b..0000000
--- 
a/extras/indexing/src/main/java/mvm/rya/indexing/entity/storage/mongo/RyaTypeDocumentConverter.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/**
- * 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/07643eb7/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
deleted file mode 100644
index 2d171d7..0000000
--- 
a/extras/indexing/src/main/java/mvm/rya/indexing/entity/storage/mongo/TypeDocumentConverter.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * 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/07643eb7/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
deleted file mode 100644
index 627b879..0000000
--- 
a/extras/indexing/src/main/java/mvm/rya/indexing/entity/update/BaseEntityIndexer.java
+++ /dev/null
@@ -1,266 +0,0 @@
-/**
- * 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/07643eb7/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
deleted file mode 100644
index 6d74836..0000000
--- 
a/extras/indexing/src/main/java/mvm/rya/indexing/entity/update/EntityIndexer.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
- * 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/07643eb7/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
deleted file mode 100644
index 6f883d4..0000000
--- 
a/extras/indexing/src/main/java/mvm/rya/indexing/entity/update/EntityUpdater.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/**
- * 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/07643eb7/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
deleted file mode 100644
index 94550ac..0000000
--- 
a/extras/indexing/src/main/java/mvm/rya/indexing/entity/update/mongo/MongoEntityIndexer.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/**
- * 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/07643eb7/extras/indexing/src/main/java/org/apache/rya/indexing/entity/EntityIndexException.java
----------------------------------------------------------------------
diff --git 
a/extras/indexing/src/main/java/org/apache/rya/indexing/entity/EntityIndexException.java
 
b/extras/indexing/src/main/java/org/apache/rya/indexing/entity/EntityIndexException.java
new file mode 100644
index 0000000..61efc91
--- /dev/null
+++ 
b/extras/indexing/src/main/java/org/apache/rya/indexing/entity/EntityIndexException.java
@@ -0,0 +1,57 @@
+/**
+ * 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 org.apache.rya.indexing.entity;
+
+import org.apache.rya.indexing.entity.model.TypedEntity;
+
+/**
+ * An operation over the {@link TypedEntity} index failed to complete.
+ */
+public class EntityIndexException extends Exception {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Constructs a new exception with the specified detail message.  The
+     * cause is not initialized, and may subsequently be initialized by
+     * a call to {@link #initCause}.
+     *
+     * @param   message   the detail message. The detail message is saved for
+     *          later retrieval by the {@link #getMessage()} method.
+     */
+    public EntityIndexException(final String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message and
+     * cause.  <p>Note that the detail message associated with
+     * {@code cause} is <i>not</i> automatically incorporated in
+     * this exception's detail message.
+     *
+     * @param  message the detail message (which is saved for later retrieval
+     *         by the {@link #getMessage()} method).
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method).  (A <tt>null</tt> value is
+     *         permitted, and indicates that the cause is nonexistent or
+     *         unknown.)
+     */
+    public EntityIndexException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/07643eb7/extras/indexing/src/main/java/org/apache/rya/indexing/entity/model/Entity.java
----------------------------------------------------------------------
diff --git 
a/extras/indexing/src/main/java/org/apache/rya/indexing/entity/model/Entity.java
 
b/extras/indexing/src/main/java/org/apache/rya/indexing/entity/model/Entity.java
new file mode 100644
index 0000000..c37eed3
--- /dev/null
+++ 
b/extras/indexing/src/main/java/org/apache/rya/indexing/entity/model/Entity.java
@@ -0,0 +1,323 @@
+/**
+ * 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 org.apache.rya.indexing.entity.model;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Optional;
+
+import org.apache.rya.api.domain.RyaURI;
+import org.apache.rya.indexing.entity.storage.EntityStorage;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+
+/**
+ * An {@link Entity} is a named concept that has at least one defined structure
+ * and a bunch of values that fit within each of those structures. A structure 
is
+ * defined by a {@link Type}. A value that fits within that Type is a {@link 
Property}.
+ * </p>
+ * For example, suppose we want to represent a type of icecream as an Entity.
+ * First we must define what properties an icecream entity may have:
+ * <pre>
+ *                 Type ID: &lt;urn:icecream>
+ *              Properties: &lt;urn:brand>
+ *                          &lt;urn:flavor>
+ *                          &lt;urn:ingredients>
+ *                          &lt;urn:nutritionalInformation>
+ * </pre>
+ * Now we can represent our icecream whose brand is "Awesome Icecream" and 
whose
+ * flavor is "Chocolate", but has no ingredients or nutritional information, as
+ * an Entity by doing the following:
+ * <pre>
+ * 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();
+ * </pre>
+ * The two types of Entities that may be created are implicit and explicit.
+ * An implicit Entity is one who has at least one {@link Property} that matches
+ * the {@link Type}, but nothing has explicitly indicated it is of  that Type.
+ * Once something has done so, it is an explicitly typed Entity.
+ */
+@Immutable
+
+public class Entity {
+
+    private final RyaURI subject;
+    private final ImmutableList<RyaURI> explicitTypeIds;
+
+    // First key is Type ID.
+    // Second key is Property Name.
+    // Value is the Property value for a specific type.
+    private final ImmutableMap<RyaURI, ImmutableMap<RyaURI, Property>> 
properties;
+
+    private final int version;
+
+    /**
+     * To construct an instances of this class, use {@link Builder}.
+     */
+    private Entity(
+            final RyaURI subject,
+            final ImmutableList<RyaURI> explicitTypeIds,
+            final ImmutableMap<RyaURI, ImmutableMap<RyaURI, Property>> 
typeProperties,
+            int version) {
+        subject = requireNonNull(subject);
+        explicitTypeIds = requireNonNull(explicitTypeIds);
+        properties = requireNonNull(typeProperties);
+        version = version;
+    }
+
+    /**
+     * @return Identifies the thing that is being represented as an Entity.
+     */
+    public RyaURI getSubject() {
+        return subject;
+    }
+
+    /**
+     * @return {@link Type}s that have been explicitly applied to the {@link 
Entity}.
+     */
+    public ImmutableList<RyaURI> getExplicitTypeIds() {
+        return explicitTypeIds;
+    }
+
+    /**
+     * @return All {@link Property}s that have been set for the Entity, 
grouped by Type ID.
+     */
+    public ImmutableMap<RyaURI, ImmutableMap<RyaURI, Property>> 
getProperties() {
+        return properties;
+    }
+
+    /**
+     * @return The version of this Entity. This value is used by the {@link 
EntityStorage}
+     *   to prevent stale updates.
+     */
+    public int getVersion() {
+        return version;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(subject, explicitTypeIds, properties, version);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if(this == o) {
+            return true;
+        }
+        if(o instanceof Entity) {
+            final Entity entity = (Entity) o;
+            return Objects.equals(subject, entity.subject) &&
+                    Objects.equals(explicitTypeIds, entity.explicitTypeIds) &&
+                    Objects.equals(properties, entity.properties) &&
+                    version == entity.version;
+        }
+        return false;
+    }
+
+    /**
+     * Builds an {@link TypedEntity} using this object's values for the 
specified {@link Type}.
+     *
+     * @param typeId - The ID of the Type the TypedEntity will be for. (not 
null)
+     * @return A TypedEntity using this object's values if any properties for 
the Type
+     *    are present or if the Type was explicitly set. Otherwise an empty 
{@link Optional}.
+     */
+    public Optional<TypedEntity> makeTypedEntity(RyaURI typeId) {
+        requireNonNull(typeId);
+
+        final boolean explicitlyHasType = explicitTypeIds.contains(typeId);
+        final boolean hasTypesProperties = properties.containsKey(typeId);
+
+        // The case where the MongoEntity can be represented as the typeId's 
Type.
+        if(explicitlyHasType || hasTypesProperties) {
+            // Set required fields.
+            final TypedEntity.Builder builder = TypedEntity.builder()
+                    .setId( subject )
+                    .setTypeId( typeId )
+                    .setExplicitelyTyped( explicitTypeIds.contains(typeId) );
+
+            // Set Type's properties if present.
+            if(properties.containsKey(typeId)) {
+                properties.get(typeId).forEach( (propertyName, property) -> 
builder.setProperty(property));
+            }
+
+            return Optional.of( builder.build() );
+        }
+
+        // This MongoEntity can not be represented by the typeId's Type.
+        return Optional.empty();
+    }
+
+    /**
+     * @return An empty instance of {@link Builder}.
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Create a {@link Builder} initialized with an {@link Entity}'s values.
+     *
+     * @param entity - The Entity the builder will be based on. (not null)
+     * @return A {@link Builder} loaded with {@code entity}'s values.
+     */
+    public static Builder builder(Entity entity) {
+        return new Builder(entity);
+    }
+
+    /**
+     * Builds instances of {@link Entity}.
+     */
+    @ParametersAreNonnullByDefault
+    public static class Builder {
+
+        private RyaURI subject = null;
+        private final List<RyaURI> explicitTypes = new ArrayList<>();
+        private final Map<RyaURI, Map<RyaURI, Property>> properties = new 
HashMap<>();
+
+        private int version = 0;
+
+        /**
+         * Constructs an empty instance of {@link Builder}.
+         */
+        public Builder() { }
+
+        /**
+         * Constructs an instance of {@link Builder}.
+         *
+         * @param entity - The Entity the builder will be based on. (not null)
+         */
+        public Builder(Entity entity) {
+            requireNonNull(entity);
+
+            subject = entity.getSubject();
+            explicitTypes.addAll( entity.getExplicitTypeIds() );
+
+            for(final Entry<RyaURI, ImmutableMap<RyaURI, Property>> entry : 
entity.getProperties().entrySet()) {
+                properties.put(entry.getKey(), 
Maps.newHashMap(entry.getValue()));
+            }
+
+            version = entity.getVersion();
+        }
+
+        /**
+         * @param subject - Identifies the {@link TypedEntity}.
+         * @return This {@link Builder} so that method invocations may be 
chained.
+         */
+        public Builder setSubject(@Nullable final RyaURI subject) {
+            subject = subject;
+            return this;
+        }
+
+        /**
+         * @param typeId - A {@link Type} that has been explicity set for the 
{@link TypedEntity}.
+         * @return This {@link Builder} so that method invocations may be 
chained.
+         */
+        public Builder setExplicitType(@Nullable final RyaURI typeId) {
+            if(typeId != null) {
+                explicitTypes.add(typeId);
+            }
+            return this;
+        }
+
+        /**
+         * Removed a Type ID from the set of explicit Type IDs.
+         *
+         * @param typeId - The Type ID to remove from the set of explicit 
types.
+         * @return This {@link Builder} so that method invocations may be 
chained.
+         */
+        public Builder unsetExplicitType(@Nullable final RyaURI typeId) {
+            if(typeId != null) {
+                explicitTypes.remove(typeId);
+            }
+            return this;
+        }
+
+        /**
+         * Adds a {@link Property} for a specific {@link Type} of {@link 
TypedEntity}.
+         *
+         * @param typeId - The Type the Property is for.
+         * @param property - The Property values to add.
+         * @return This {@link Builder} so that method invocations may be 
chained.
+         */
+        public Builder setProperty(@Nullable final RyaURI typeId, @Nullable 
final Property property) {
+            if(typeId != null && property != null) {
+                if(!properties.containsKey(typeId)) {
+                    properties.put(typeId, new HashMap<>());
+                }
+
+                properties.get(typeId).put(property.getName(), property);
+            }
+            return this;
+        }
+
+        /**
+         * Removes a {@link Property} for a specific {@link Type} of {@link 
TypedEntity}.
+         *
+         * @param typeId - The Type the Property will be removed from.
+         * @param propertyName - The name of the Property to remove.
+         * @return This {@link Builder} so that method invocations may be 
chained.
+         */
+        public Builder unsetProperty(@Nullable final RyaURI typeId, @Nullable 
final RyaURI propertyName) {
+            if(typeId != null && propertyName != null) {
+                if(properties.containsKey(typeId)) {
+                    final Map<RyaURI, Property> typedProperties = 
properties.get(typeId);
+                    if(typedProperties.containsKey(propertyName)) {
+                        typedProperties.remove(propertyName);
+                    }
+                }
+            }
+            return this;
+        }
+
+        /**
+         * @param version - The version of this Entity. This value is used by 
the
+         * {@link EntityStorage} to prevent stale updates.
+         * @return This {@link Builder} so that method invocations may be 
chained.
+         */
+        public Builder setVersion(int version) {
+            version = version;
+            return this;
+        }
+
+        /**
+         * @return Builds an instance of {@link Entity} using this builder's 
values.
+         */
+        public Entity build() {
+            final ImmutableMap.Builder<RyaURI, ImmutableMap<RyaURI, Property>> 
propertiesBuilder = ImmutableMap.builder();
+            for(final Entry<RyaURI, Map<RyaURI, Property>> entry : 
properties.entrySet()) {
+                propertiesBuilder.put(entry.getKey(), ImmutableMap.copyOf( 
entry.getValue() ));
+            }
+
+            return new Entity(subject,
+                    ImmutableList.copyOf( explicitTypes ),
+                    propertiesBuilder.build(),
+                    version);
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/07643eb7/extras/indexing/src/main/java/org/apache/rya/indexing/entity/model/Property.java
----------------------------------------------------------------------
diff --git 
a/extras/indexing/src/main/java/org/apache/rya/indexing/entity/model/Property.java
 
b/extras/indexing/src/main/java/org/apache/rya/indexing/entity/model/Property.java
new file mode 100644
index 0000000..4388024
--- /dev/null
+++ 
b/extras/indexing/src/main/java/org/apache/rya/indexing/entity/model/Property.java
@@ -0,0 +1,83 @@
+/**
+ * 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 org.apache.rya.indexing.entity.model;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.Objects;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+import javax.annotation.concurrent.Immutable;
+
+import mvm.rya.api.domain.RyaType;
+import mvm.rya.api.domain.RyaURI;
+
+/**
+ * A value that has been set for an {@link TypedEntity}.
+ */
+@Immutable
+@ParametersAreNonnullByDefault
+public class Property {
+
+    private final RyaURI name;
+    private final RyaType value;
+
+    /**
+     * Constructs an instance of {@link Property}.
+     *
+     * @param name - Uniquely identifies the {@link Property}. (not null)
+     * @param value - The value of the {@link Property}. (not null)
+     */
+    public Property(final RyaURI name, final RyaType value) {
+        this.name = requireNonNull(name);
+        this.value = requireNonNull(value);
+    }
+
+    /**
+     * @return Uniquely identifies the {@link Property}.
+     */
+    public RyaURI getName() {
+        return name;
+    }
+
+    /**
+     * @return The value of the {@link Property}.
+     */
+    public RyaType getValue() {
+        return value;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(name, value);
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if(this == o) {
+            return true;
+        }
+        if(o instanceof Property) {
+            final Property field = (Property) o;
+            return Objects.equals(name, field.name) &&
+                    Objects.equals(value, field.value);
+        }
+        return false;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/07643eb7/extras/indexing/src/main/java/org/apache/rya/indexing/entity/model/Type.java
----------------------------------------------------------------------
diff --git 
a/extras/indexing/src/main/java/org/apache/rya/indexing/entity/model/Type.java 
b/extras/indexing/src/main/java/org/apache/rya/indexing/entity/model/Type.java
new file mode 100644
index 0000000..7d8e0ee
--- /dev/null
+++ 
b/extras/indexing/src/main/java/org/apache/rya/indexing/entity/model/Type.java
@@ -0,0 +1,103 @@
+/**
+ * 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 org.apache.rya.indexing.entity.model;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.Objects;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+import javax.annotation.concurrent.Immutable;
+
+import org.apache.rya.indexing.entity.storage.TypeStorage;
+
+import com.google.common.collect.ImmutableSet;
+
+import mvm.rya.api.domain.RyaURI;
+
+/**
+ * Defines the structure of an {@link TypedEntity}.
+ * </p>
+ * For example, suppose you want a {@link Type} that defines what properties 
are
+ * available for icecream. It could be modeled like this:
+ * <pre>
+ *                 Type ID: &lt;urn:icecream>
+ *              Properties: &lt;urn:brand>
+ *                          &lt;urn:flavor>
+ *                          &lt;urn:ingredients>
+ *                          &lt;urn:nutritionalInformation>
+ * </pre>
+ */
+@Immutable
+@ParametersAreNonnullByDefault
+public class Type {
+
+    /**
+     * Uniquely identifies the Type within a {@link TypeStorage}.
+     */
+    private final RyaURI id;
+
+    /**
+     * The names of {@link Property}s that may be part of an {@link 
TypedEntity} of this type.
+     */
+    private final ImmutableSet<RyaURI> propertyNames;
+
+    /**
+     * Constructs an instance of {@link Type}.
+     *
+     * @param id - Uniquely identifies the Type within a {@link TypeStorage}. 
(not null)
+     * @param propertyNames - The names of {@link Property}s that may be part 
of an {@link TypedEntity} of this type. (not null)
+     */
+    public Type(final RyaURI id, final ImmutableSet<RyaURI> propertyNames) {
+        this.id = requireNonNull(id);
+        this.propertyNames = requireNonNull(propertyNames);
+    }
+
+    /**
+     * @return Uniquely identifies the Type within a {@link TypeStorage}.
+     */
+    public RyaURI getId() {
+        return id;
+    }
+
+    /**
+     * @return The names of {@link Property}s that may be part of an {@link 
TypedEntity} of this type.
+     */
+    public ImmutableSet<RyaURI> getPropertyNames() {
+        return propertyNames;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(id, propertyNames);
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if(this == o) {
+            return true;
+        }
+        if(o instanceof Type) {
+            final Type type = (Type) o;
+            return Objects.equals(id, type.id) &&
+                    Objects.equals(propertyNames, type.propertyNames);
+        }
+        return false;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/07643eb7/extras/indexing/src/main/java/org/apache/rya/indexing/entity/model/TypedEntity.java
----------------------------------------------------------------------
diff --git 
a/extras/indexing/src/main/java/org/apache/rya/indexing/entity/model/TypedEntity.java
 
b/extras/indexing/src/main/java/org/apache/rya/indexing/entity/model/TypedEntity.java
new file mode 100644
index 0000000..a49c8d2
--- /dev/null
+++ 
b/extras/indexing/src/main/java/org/apache/rya/indexing/entity/model/TypedEntity.java
@@ -0,0 +1,242 @@
+/**
+ * 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 org.apache.rya.indexing.entity.model;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+import javax.annotation.Nullable;
+import javax.annotation.ParametersAreNonnullByDefault;
+import javax.annotation.concurrent.Immutable;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableMap;
+
+import mvm.rya.api.domain.RyaType;
+import mvm.rya.api.domain.RyaURI;
+
+/**
+ * A {@link TypedEntity} is a view of an {@link Entity} that has had a specific
+ * {@link Type} applied to it.
+ */
+@Immutable
+@ParametersAreNonnullByDefault
+public class TypedEntity {
+
+    /**
+     * The Subject of the {@link Entity} this view was derived from.
+     */
+    private final RyaURI subject;
+
+    /**
+     * The ID of the {@link Type} that defines the structure of this 
TypedEntity.
+     */
+    private final RyaURI typeId;
+
+    /**
+     * {@code true} if the Entity's Type has been explicitly set to the {@link 
#typeId}
+     * value; {@code false} if it is implicit (this Entity only exists because 
it has
+     * properties that happen to match that type's properties).
+     */
+    private final boolean explicitlyTyped;
+
+    /**
+     * The optional {@link Property} values of this {@link TypedEntity}.
+     * </p>
+     * They are mapped from property name to property object for quick lookup.
+     */
+    private final ImmutableMap<RyaURI, Property> optionalFields;
+
+    /**
+     * Constructs an instance of {@link TypedEntity}.
+     *
+     * @param subject - The Subject of the {@link Entity} this view was 
derived from. (not null)
+     * @param dataTypeId - The ID of the {@link Type} that defines the 
structure of this Entity. (not null)
+     * @param explicitlyTyped - {@code true} if the Entity's Type has been 
explicitly set to the
+     *   {@link #typeId} value; {@code false} if it is implicit (this Entity 
only exists because
+     *   it has properties that happen to match that type's properties).
+     * @param properties - The optional {@link Property} values of this {@link 
TypedEntity}. (not null)
+     */
+    private TypedEntity(final RyaURI subject,
+            final RyaURI dataTypeId,
+            boolean explicitlyTyped,
+            final ImmutableMap<RyaURI, Property> optionalFields) {
+        this.subject = requireNonNull(subject);
+        this.typeId = requireNonNull(dataTypeId);
+        this.optionalFields = requireNonNull(optionalFields);
+        this.explicitlyTyped = explicitlyTyped;
+    }
+
+    /**
+     * @return The Subject of the {@link Entity} this view was derived from.
+     */
+    public RyaURI getSubject() {
+        return subject;
+    }
+
+    /**
+     * @return The ID of the {@link Type} that defines the structure of this 
Entity.
+     */
+    public RyaURI getTypeId() {
+        return typeId;
+    }
+
+    /**
+     * @return {@code true} if the Entity's Type has been explicitly set to 
the {@link #typeId}
+     *   value; {@code false} if it is implicit (this Entity only exists 
because it has
+     *   properties that happen to match that type's properties).
+     */
+    public boolean isExplicitlyTyped() {
+        return explicitlyTyped;
+    }
+
+    /**
+     * @return The optional {@link Property} values of this {@link 
TypedEntity}.
+     */
+    public ImmutableCollection<Property> getProperties() {
+        return optionalFields.values();
+    }
+
+    /**
+     * Get the value of a specific {@link Property} of this {@link TypedEntity}
+     * if the property has been set.
+     *
+     * @param propertyName - The name of {@link Property} that may be in this 
Entity. (not null)
+     * @return The value of the Property if it has been set.
+     */
+    public Optional<RyaType> getPropertyValue(final RyaURI propertyName) {
+        requireNonNull(propertyName);
+
+        final Property field = optionalFields.get(propertyName);
+        return field == null ?
+                Optional.absent() :
+                Optional.of( field.getValue() );
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(subject, typeId, optionalFields);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if(this == o) {
+            return true;
+        }
+        if(o instanceof TypedEntity) {
+            final TypedEntity other = (TypedEntity) o;
+            return Objects.equals(subject, other.subject) &&
+                    Objects.equals(typeId, other.typeId) &&
+                    Objects.equals(optionalFields, other.optionalFields);
+        }
+        return false;
+    }
+
+    /**
+     * @return An empty instance of {@link Builder}.
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Makes a {@link Builder} that is populated with an existing {@link 
TypedEntity}.
+     *
+     * @param entity - The initial values of the builder. (not null)
+     * @return An instance of {@link Builder} loaded with {@code entity}'s 
values.
+     */
+    public static Builder builder(TypedEntity entity) {
+        requireNonNull(entity);
+
+        final Builder builder = builder()
+                .setId(entity.getSubject())
+                .setTypeId(entity.getTypeId());
+
+        entity.getProperties().forEach(builder::setProperty);
+
+        return builder;
+    }
+
+    /**
+     * Builds instances of {@link TypedEntity}.
+     */
+    @ParametersAreNonnullByDefault
+    public static class Builder {
+
+        private RyaURI subject;
+        private RyaURI typeId;
+        private boolean explicitlyTyped = false;
+        private final Map<RyaURI, Property> properties = new HashMap<>();
+
+        /**
+         * @param subject - The Subject of the {@link Entity} this view was 
derived from.
+         * @return This {@link Builder} so that method invocations may be 
chained.
+         */
+        public Builder setId(@Nullable final RyaURI subject) {
+            this.subject = subject;
+            return this;
+        }
+
+        /**
+         * @param typeId -  The ID of the {@link Type} that defines the 
structure of this Entity.
+         * @return This {@link Builder} so that method invocations may be 
chained.
+         */
+        public Builder setTypeId(@Nullable final RyaURI typeId) {
+            this.typeId = typeId;
+            return this;
+        }
+
+        /**
+         * @param explicitlyTyped - {@code true} if the Entity's Type has been 
explicitly
+         * set to the {@link #typeId} value; {@code false} if it is implicit 
(this Entity
+         * only exists because it has properties that happen to match that 
type's properties).
+         * @return This {@link Builder} so that method invocations may be 
chained.
+         */
+        public Builder setExplicitelyTyped(boolean explicitlyTyped) {
+            this.explicitlyTyped = explicitlyTyped;
+            return this;
+        }
+
+        /**
+         * @param property - A {@link Property} of the {@link TypedEntity}.
+         * @return This {@link Builder} so that method invocations may be 
chained.
+         */
+        public Builder setProperty(@Nullable final Property property) {
+            if(property != null) {
+                properties.put(property.getName(), property);
+            }
+            return this;
+        }
+
+        /**
+         * @return An instance of {@link TypedEntity} built with this 
builder's values.
+         */
+        public TypedEntity build() {
+            return new TypedEntity(
+                    subject,
+                    typeId,
+                    explicitlyTyped,
+                    ImmutableMap.copyOf(properties));
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/07643eb7/extras/indexing/src/main/java/org/apache/rya/indexing/entity/query/EntityQueryNode.java
----------------------------------------------------------------------
diff --git 
a/extras/indexing/src/main/java/org/apache/rya/indexing/entity/query/EntityQueryNode.java
 
b/extras/indexing/src/main/java/org/apache/rya/indexing/entity/query/EntityQueryNode.java
new file mode 100644
index 0000000..bb14922
--- /dev/null
+++ 
b/extras/indexing/src/main/java/org/apache/rya/indexing/entity/query/EntityQueryNode.java
@@ -0,0 +1,238 @@
+/**
+ * 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 org.apache.rya.indexing.entity.query;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Optional;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
+import org.apache.rya.indexing.entity.model.Type;
+import org.apache.rya.indexing.entity.storage.EntityStorage;
+import org.openrdf.model.vocabulary.RDF;
+import org.openrdf.query.BindingSet;
+import org.openrdf.query.QueryEvaluationException;
+import org.openrdf.query.algebra.StatementPattern;
+import org.openrdf.query.algebra.Var;
+import org.openrdf.query.algebra.evaluation.impl.ExternalSet;
+
+import com.google.common.collect.ImmutableMap;
+
+import info.aduna.iteration.CloseableIteration;
+import mvm.rya.api.domain.RyaURI;
+import mvm.rya.rdftriplestore.evaluation.ExternalBatchingIterator;
+
+/**
+ * TODO impl, test, doc
+ */
+@ParametersAreNonnullByDefault
+public class EntityQueryNode extends ExternalSet implements 
ExternalBatchingIterator {
+
+    /**
+     * The RyaURI that when used as the Predicate of a Statement Pattern 
indicates the Type of the Entities.
+     */
+    private static final RyaURI TYPE_ID_URI = new RyaURI(RDF.TYPE.toString());
+
+    // Provided at construction time.
+    private final Type type;
+    private final Collection<StatementPattern> patterns;
+    private final EntityStorage entities;
+
+    // Information about the subject of the patterns.
+    private final boolean subjectIsConstant;
+    private final Optional<String> subjectConstant;
+    private final Optional<String> subjectVar;
+
+    // Information about the objects of the patterns.
+
+    // XXX what does this map? property name -> binding variable?
+    // for any property of the entity that has a variable, have to fill it in?
+    private final ImmutableMap<RyaURI, String> objectVariables;
+
+
+    /**
+     * Constructs an instance of {@link EntityQueryNode}.
+     *
+     * @param type - The type of {@link Entity} this node matches. (not null)
+     * @param patterns - The query StatementPatterns that are solved using an
+     *   Entity of the Type. (not null)
+     * @param entities - The {@link EntityStorage} that will be searched to 
match
+     *   {@link BindingSet}s when evaluating a query. (not null)
+     */
+    public EntityQueryNode(final Type type, final Collection<StatementPattern> 
patterns, final EntityStorage entities) throws IllegalStateException {
+        this.type = requireNonNull(type);
+        this.patterns = requireNonNull(patterns);
+        this.entities = requireNonNull(entities);
+
+        // Subject based preconditions.
+        verifySameSubjects(patterns);
+
+        // Predicate based preconditions.
+        verifyAllPredicatesAreConstants(patterns);
+        verifyHasCorrectTypePattern(type, patterns);
+        verifyAllPredicatesPartOfType(type, patterns);
+
+        // The Subject may either be constant or a variable.
+        final Var subject = patterns.iterator().next().getSubjectVar();
+        subjectIsConstant = subject.isConstant();
+        if(subjectIsConstant) {
+            subjectConstant = Optional.of( subject.getValue().toString() );
+            subjectVar = Optional.empty();
+        } else {
+            subjectConstant = Optional.empty();
+            subjectVar = Optional.of( subject.getName() );
+        }
+
+        // TODO Also, map each variable that is in an Object spot each 
variable can be mapped to a property name as well
+        // Processing note:
+        // Any constant that appears in the Object portion of the SP will be 
used to make sure they match.
+
+        objectVariables = null;
+    }
+
+    /**
+     * Verify the Subject for all of the patterns is the same.
+     *
+     * @param patterns - The patterns to check.
+     * @throws IllegalStateException If all of the Subjects are not the same.
+     */
+    private static void verifySameSubjects(Collection<StatementPattern> 
patterns) throws IllegalStateException {
+        requireNonNull(patterns);
+
+        final Iterator<StatementPattern> it = patterns.iterator();
+        final Var subject = it.next().getSubjectVar();
+
+        while(it.hasNext()) {
+            final StatementPattern pattern = it.next();
+            if(!pattern.getSubjectVar().equals(subject)) {
+                throw new IllegalStateException("At least one of the patterns 
has a different subject from the others. " +
+                        "All subjects must be the same.");
+            }
+        }
+    }
+
+    /**
+     * Verifies all of the Statement Patterns have Constants for their 
predicates.
+     *
+     * @param patterns - The patterns to check. (not null)
+     * @throws IllegalStateException A pattern has a variable predicate.
+     */
+    private static void 
verifyAllPredicatesAreConstants(Collection<StatementPattern> patterns) throws 
IllegalStateException {
+        requireNonNull(patterns);
+
+        for(final StatementPattern pattern : patterns) {
+            if(!pattern.getPredicateVar().isConstant()) {
+                throw new IllegalStateException("The Predicate of a Statement 
Pattern must be constant. Pattern: " + pattern);
+            }
+        }
+    }
+
+    /**
+     * Verifies a single Statement Pattern defines the Type of Entity this 
query node matches.
+     *
+     * @param type - The expected Type. (not null)
+     * @param patterns - The patterns to check. (not null)
+     * @throws IllegalStateException No Type or the wrong Type is specified by 
the patterns.
+     */
+    private static void verifyHasCorrectTypePattern(Type type, 
Collection<StatementPattern> patterns) throws IllegalStateException {
+        requireNonNull(type);
+        requireNonNull(patterns);
+
+        boolean typeFound = false;
+
+        for(final StatementPattern pattern : patterns) {
+            final RyaURI predicate = new 
RyaURI(pattern.getPredicateVar().getValue().toString());
+
+            if(predicate.equals(TYPE_ID_URI)) {
+                final RyaURI typeId = new RyaURI( 
pattern.getObjectVar().getValue().stringValue() );
+                if(typeId.equals(type.getId())) {
+                    typeFound = true;
+                } else {
+                    throw new IllegalStateException("Statement Pattern 
encountred for a Type that does not match the expected Type." +
+                            " Expected Type = '" + type.getId().getData() + "' 
Found Type = '" + typeId.getData() + "'");
+                }
+            }
+        }
+
+        if(!typeFound) {
+            throw new IllegalStateException("The collection of Statement 
Patterns that this node matches must define which Type they match.");
+        }
+    }
+
+    /**
+     * Verify all of the patterns have predicates that match one of the Type's 
property names.
+     *
+     * @param type - The Type the patterns match. (not null)
+     * @param patterns - The patterns to check.
+     * @throws IllegalStateException If any of the non-type defining Statement 
Patterns
+     *   contain a predicate that does not match one of the Type's property 
names.
+     */
+    private static void verifyAllPredicatesPartOfType(Type type, 
Collection<StatementPattern> patterns) throws IllegalStateException {
+        requireNonNull(type);
+        requireNonNull(patterns);
+
+        for(final StatementPattern pattern : patterns) {
+            // Skip TYPE patterns.
+            final RyaURI predicate = new RyaURI( 
pattern.getPredicateVar().getValue().toString() );
+            if(predicate.equals(TYPE_ID_URI)) {
+                continue;
+            }
+
+            if(!type.getPropertyNames().contains(predicate)) {
+                throw new IllegalStateException("The Predicate of a Statement 
Pattern must be a property name for the Type. " +
+                        "Type ID: '" + type.getId().getData() + "' Pattern: " 
+ pattern);
+            }
+        }
+    }
+
+
+
+
+
+
+    @Override
+    public CloseableIteration<BindingSet, QueryEvaluationException> 
evaluate(Collection<BindingSet> bindingSets) throws QueryEvaluationException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public CloseableIteration<BindingSet, QueryEvaluationException> 
evaluate(BindingSet bindingSet) throws QueryEvaluationException {
+        requireNonNull(bindingSet);
+
+        // ... ok, so if the subject needs to be filled in, then we need to 
see if the subject variable is in the binding set.
+        // if it is, fetch that value and then fetch the entity for the 
subject.
+
+        // if it isn't, fetch the entity for the constant?
+
+
+        // RETURN AN EMPTY ITERATION IF IT CAN NOT FILL IT IN!
+
+        // for all variables in the OBJECT portion of the SPs, fill 'em in 
using the entity that is stored in the index.
+
+        // x = alice's SSN
+        // y = blue  <-- how do i know this is for urn:eye property? FROM THE 
STATEMENT PATTERN. look for the ?y in the SP, and that has the property name in 
it.
+
+        // TODO Auto-generated method stub
+        return null;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/07643eb7/extras/indexing/src/main/java/org/apache/rya/indexing/entity/storage/CloseableIterator.java
----------------------------------------------------------------------
diff --git 
a/extras/indexing/src/main/java/org/apache/rya/indexing/entity/storage/CloseableIterator.java
 
b/extras/indexing/src/main/java/org/apache/rya/indexing/entity/storage/CloseableIterator.java
new file mode 100644
index 0000000..3b2e10f
--- /dev/null
+++ 
b/extras/indexing/src/main/java/org/apache/rya/indexing/entity/storage/CloseableIterator.java
@@ -0,0 +1,29 @@
+/**
+ * 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 org.apache.rya.indexing.entity.storage;
+
+import java.io.Closeable;
+import java.util.Iterator;
+
+/**
+ * An {@link Iterator} that is also {@link Closeable}.
+ *
+ * @param <T> - The type of object that will be iterated over.
+ */
+public interface CloseableIterator<T> extends Iterator<T>, Closeable { }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/07643eb7/extras/indexing/src/main/java/org/apache/rya/indexing/entity/storage/EntityStorage.java
----------------------------------------------------------------------
diff --git 
a/extras/indexing/src/main/java/org/apache/rya/indexing/entity/storage/EntityStorage.java
 
b/extras/indexing/src/main/java/org/apache/rya/indexing/entity/storage/EntityStorage.java
new file mode 100644
index 0000000..44db8e2
--- /dev/null
+++ 
b/extras/indexing/src/main/java/org/apache/rya/indexing/entity/storage/EntityStorage.java
@@ -0,0 +1,154 @@
+/**
+ * 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 org.apache.rya.indexing.entity.storage;
+
+import java.util.Optional;
+import java.util.Set;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
+import org.apache.rya.indexing.entity.EntityIndexException;
+import org.apache.rya.indexing.entity.model.Entity;
+import org.apache.rya.indexing.entity.model.Property;
+import org.apache.rya.indexing.entity.model.Type;
+import org.apache.rya.indexing.entity.model.TypedEntity;
+
+import mvm.rya.api.domain.RyaURI;
+
+/**
+ * Stores and provides access to {@link Entity}s.
+ */
+@ParametersAreNonnullByDefault
+public interface EntityStorage {
+
+    /**
+     * Creates a new {@link Entity} within the storage. The new Entity's 
subject must be unique.
+     *
+     * @param entity - The {@link Entity} to create. (not null)
+     * @throws EntityAlreadyExistsException An {@link Entity} could not be 
created because one already exists for the Subject.
+     * @throws EntityStorageException A problem occurred while creating the 
Entity.
+     */
+    public void create(Entity entity) throws EntityAlreadyExistsException, 
EntityStorageException;
+
+    /**
+     * Get an {@link Entity} from the storage by its subject.
+     *
+     * @param subject - Identifies which {@link Entity} to get. (not null)
+     * @return The {@link Entity} if one exists for the subject.
+     * @throws EntityStorageException A problem occurred while fetching the 
Entity from the storage.
+     */
+    public Optional<Entity> get(RyaURI subject) throws EntityStorageException;
+
+    /**
+     * Update the state of an {@link Entity}.
+     *
+     * @param old - The Entity the changes were applied to. (not null)
+     * @param updated - The updated Entity to store. (not null)
+     * @throws StaleUpdateException The {@code old} Entity does not match any 
Entities that are stored.
+     * @throws EntityStorageException A problem occurred while updating the 
Entity within the storage.
+     */
+    public void update(Entity old, Entity updated) throws 
StaleUpdateException, EntityStorageException;
+
+    /**
+     * Search the stored {@link Entity}s that have a specific {@link Type} as
+     * well as the provided {@link Property} values.
+     *
+     * @param type - The {@link Type} of the Entities. (not null)
+     * @param properties - The {@link Property} values that must be set on the 
Entity. (not null)
+     * @return A {@link CloseableIterator} over the {@link TypedEntity}s that 
match the search parameters.
+     * @throws EntityStorageException A problem occurred while searching the 
storage.
+     */
+    public CloseableIterator<TypedEntity> search(Type type, Set<Property> 
properties) throws EntityStorageException;
+
+    /**
+     * Deletes an {@link Entity} from the storage.
+     *
+     * @param subject -Identifies which {@link Entity} to delete. (not null)
+     * @return {@code true} if something was deleted; otherwise {@code false}.
+     * @throws EntityStorageException A problem occurred while deleting from 
the storage.
+     */
+    public boolean delete(RyaURI subject) throws EntityStorageException;
+
+    /**
+     * Indicates a problem while interacting with an {@link EntityStorage}.
+     */
+    public static class EntityStorageException extends EntityIndexException {
+        private static final long serialVersionUID = 1L;
+
+        /**
+         * Constructs a new exception with the specified detail message.  The
+         * cause is not initialized, and may subsequently be initialized by
+         * a call to {@link #initCause}.
+         *
+         * @param   message   the detail message. The detail message is saved 
for
+         *          later retrieval by the {@link #getMessage()} method.
+         */
+        public EntityStorageException(String message) {
+            super(message);
+        }
+
+        /**
+         * Constructs a new exception with the specified detail message and
+         * cause.  <p>Note that the detail message associated with
+         * {@code cause} is <i>not</i> automatically incorporated in
+         * this exception's detail message.
+         *
+         * @param  message the detail message (which is saved for later 
retrieval
+         *         by the {@link #getMessage()} method).
+         * @param  cause the cause (which is saved for later retrieval by the
+         *         {@link #getCause()} method).  (A <tt>null</tt> value is
+         *         permitted, and indicates that the cause is nonexistent or
+         *         unknown.)
+         */
+        public EntityStorageException(String message, Throwable cause) {
+            super(message, cause);
+        }
+    }
+
+    /**
+     * An {@link Entity} could not be created because one already exists for 
the Subject.
+     */
+    public static class EntityAlreadyExistsException extends 
EntityStorageException {
+        private static final long serialVersionUID = 1L;
+
+        public EntityAlreadyExistsException(String message) {
+            super(message);
+        }
+
+        public EntityAlreadyExistsException(String message, Throwable cause) {
+            super(message, cause);
+        }
+    }
+
+    /**
+     * An {@link TypedEntity} could not be updated because the old state does 
not
+     * match the current state.
+     */
+    public static class StaleUpdateException extends EntityStorageException {
+        private static final long serialVersionUID = 1L;
+
+        public StaleUpdateException(String message) {
+            super(message);
+        }
+
+        public StaleUpdateException(String message, Throwable cause) {
+            super(message, cause);
+        }
+    }
+}
\ No newline at end of file

Reply via email to