You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@rya.apache.org by pu...@apache.org on 2017/05/09 14:09:36 UTC

[1/2] incubator-rya git commit: RYA-250 Smart URI; Closes #148

Repository: incubator-rya
Updated Branches:
  refs/heads/master 4b755c64d -> 2e71ff2a7


http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/2e71ff2a/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 1a27b8f..93915a6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -97,6 +97,9 @@ under the License.
 
         <guava.version>14.0.1</guava.version> <!-- Newest: 18.0 -->
 
+        <httpcomponents.httpclient.version>4.5.2</httpcomponents.httpclient.version> <!-- Newest: 4.5.3 -->
+        <httpcomponents.httpcore.version>4.4.4</httpcomponents.httpcore.version> <!-- Newest: 4.4.6 -->
+
         <karaf.version>2.2.11</karaf.version> <!-- Newest: 4.0.3 -->
         <mango.version>1.2.0</mango.version> <!-- Newest: 1.4.0 -->
         <antlr-runtime.version>3.4</antlr-runtime.version> <!-- Newest: 3.5.2 -->
@@ -125,7 +128,6 @@ under the License.
         <plexus.version>3.0.8</plexus.version>
         <thrift.version>0.9.1</thrift.version>
         <commons.cli.version>1.2</commons.cli.version>
-        <commons.http.version>3.0.1</commons.http.version>
         <jcommander.version>1.48</jcommander.version>
         <twitter4jstream.version>4.0.1</twitter4jstream.version>
 
@@ -484,11 +486,6 @@ under the License.
                 <artifactId>commons-cli</artifactId>
                 <version>${commons.cli.version}</version>
             </dependency>
-            <dependency>
-                <groupId>commons-httpclient</groupId>
-                <artifactId>commons-httpclient</artifactId>
-                <version>${commons.http.version}</version>
-            </dependency>
 
             <!-- Free Text Indexing -->
             <dependency>
@@ -596,6 +593,18 @@ under the License.
             </dependency>
 
             <dependency>
+                <groupId>org.apache.httpcomponents</groupId>
+                <artifactId>httpclient</artifactId>
+                <version>${httpcomponents.httpclient.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.apache.httpcomponents</groupId>
+                <artifactId>httpcore</artifactId>
+                <version>${httpcomponents.httpcore.version}</version>
+            </dependency>
+
+            <dependency>
                 <groupId>org.mockito</groupId>
                 <artifactId>mockito-all</artifactId>
                 <version>${mockito.version}</version>


[2/2] incubator-rya git commit: RYA-250 Smart URI; Closes #148

Posted by pu...@apache.org.
RYA-250 Smart URI; Closes #148


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

Branch: refs/heads/master
Commit: 2e71ff2a711fc857533f87b9af5c7258ca897823
Parents: 4b755c6
Author: eric.white <Er...@parsons.com>
Authored: Mon Feb 27 11:12:05 2017 -0500
Committer: pujav65 <pu...@gmail.com>
Committed: Tue May 9 10:09:03 2017 -0400

----------------------------------------------------------------------
 .../org/apache/rya/api/domain/RyaTypeUtils.java | 157 +++++
 extras/indexing/pom.xml                         |   5 +
 .../rya/indexing/entity/model/Entity.java       | 117 +++-
 .../storage/mongo/EntityDocumentConverter.java  |  18 +-
 .../storage/mongo/MongoEntityStorage.java       |   6 +-
 .../storage/mongo/key/MongoDbSafeKey.java       |  81 +++
 .../rya/indexing/mongodb/MongoDbSmartUri.java   | 172 +++++
 .../rya/indexing/smarturi/SmartUriAdapter.java  | 688 +++++++++++++++++++
 .../indexing/smarturi/SmartUriException.java    |  36 +
 .../rya/indexing/smarturi/SmartUriStorage.java  |  78 +++
 .../rya/indexing/mongo/MongoDbSmartUriTest.java | 333 +++++++++
 extras/indexingExample/pom.xml                  |   6 +
 extras/rya.merger/pom.xml                       |   5 -
 pom.xml                                         |  21 +-
 14 files changed, 1705 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/2e71ff2a/common/rya.api/src/main/java/org/apache/rya/api/domain/RyaTypeUtils.java
----------------------------------------------------------------------
diff --git a/common/rya.api/src/main/java/org/apache/rya/api/domain/RyaTypeUtils.java b/common/rya.api/src/main/java/org/apache/rya/api/domain/RyaTypeUtils.java
new file mode 100644
index 0000000..8ca65fc
--- /dev/null
+++ b/common/rya.api/src/main/java/org/apache/rya/api/domain/RyaTypeUtils.java
@@ -0,0 +1,157 @@
+/*
+ * 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.api.domain;
+
+import java.util.Date;
+
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+import org.joda.time.format.ISODateTimeFormat;
+import org.openrdf.model.URI;
+import org.openrdf.model.vocabulary.XMLSchema;
+
+/**
+ * Utility methods for using {@link RyaType}.
+ */
+public final class RyaTypeUtils {
+    /**
+     * Private constructor to prevent instantiation.
+     */
+    private RyaTypeUtils() {
+    }
+
+    /**
+     * Creates a boolean {@link RyaType} object.
+     * @param value the {@link Boolean} object.
+     * @return the {@link RyaType} with the data type set to
+     * {@link XMLSchema#BOOLEAN} and the data set to the specified
+     * {@code value}.
+     */
+    public static RyaType booleanRyaType(final Boolean value) {
+        return new RyaType(XMLSchema.BOOLEAN, Boolean.toString(value));
+    }
+
+    /**
+     * Creates a byte {@link RyaType} object.
+     * @param value the {@link Byte} object.
+     * @return the {@link RyaType} with the data type set to
+     * {@link XMLSchema#BYTE} and the data set to the specified {@code value}.
+     */
+    public static RyaType byteRyaType(final Byte value) {
+        return new RyaType(XMLSchema.BYTE, Byte.toString(value));
+    }
+
+    /**
+     * Creates a date {@link RyaType} object.
+     * @param value the {@link Date} object.
+     * @return the {@link RyaType} with the data type set to
+     * {@link XMLSchema#DATETIME} and the data set to the specified
+     * {@code value}.
+     */
+    public static RyaType dateRyaType(final Date value) {
+        final DateTime dateTime = new DateTime(value.getTime());
+        return dateRyaType(dateTime);
+    }
+
+    /**
+     * Creates a date/time {@link RyaType} object.
+     * @param value the {@link DateTime} object.
+     * @return the {@link RyaType} with the data type set to
+     * {@link XMLSchema#DATETIME} and the data set to the specified
+     * {@code value}.
+     */
+    public static RyaType dateRyaType(final DateTime value) {
+        final StringBuffer sb = new StringBuffer();
+        ISODateTimeFormat.dateTime().withZone(DateTimeZone.UTC).printTo(sb, value.getMillis());
+        final String formattedDate = sb.toString();
+        return new RyaType(XMLSchema.DATETIME, formattedDate);
+    }
+
+    /**
+     * Creates a double {@link RyaType} object.
+     * @param value the {@link Double} object.
+     * @return the {@link RyaType} with the data type set to
+     * {@link XMLSchema#DOUBLE} and the data set to the specified {@code value}.
+     */
+    public static RyaType doubleRyaType(final Double value) {
+        return new RyaType(XMLSchema.DOUBLE, Double.toString(value));
+    }
+
+    /**
+     * Creates a float {@link RyaType} object.
+     * @param value the {@link Float} object.
+     * @return the {@link RyaType} with the data type set to
+     * {@link XMLSchema#FLOAT} and the data set to the specified {@code value}.
+     */
+    public static RyaType floatRyaType(final Float value) {
+        return new RyaType(XMLSchema.FLOAT, Float.toString(value));
+    }
+
+    /**
+     * Creates an integer {@link RyaType} object.
+     * @param value the {@link Integer} object.
+     * @return the {@link RyaType} with the data type set to
+     * {@link XMLSchema#INTEGER} and the data set to the specified
+     * {@code value}.
+     */
+    public static RyaType intRyaType(final Integer value) {
+        return new RyaType(XMLSchema.INTEGER, Integer.toString(value));
+    }
+
+    /**
+     * Creates a long {@link RyaType} object.
+     * @param value the {@link Long} object.
+     * @return the {@link RyaType} with the data type set to
+     * {@link XMLSchema#LONG} and the data set to the specified {@code value}.
+     */
+    public static RyaType longRyaType(final Long value) {
+        return new RyaType(XMLSchema.LONG, Long.toString(value));
+    }
+
+    /**
+     * Creates a short {@link RyaType} object.
+     * @param value the {@link Short} object.
+     * @return the {@link RyaType} with the data type set to
+     * {@link XMLSchema#SHORT} and the data set to the specified {@code value}.
+     */
+    public static RyaType shortRyaType(final Short value) {
+        return new RyaType(XMLSchema.SHORT, Short.toString(value));
+    }
+
+    /**
+     * Creates a string {@link RyaType} object.
+     * @param value the {@link String} object.
+     * @return the {@link RyaType} with the data type set to
+     * {@link XMLSchema#STRING} and the data set to the specified {@code value}.
+     */
+    public static RyaType stringRyaType(final String value) {
+        return new RyaType(XMLSchema.STRING, value);
+    }
+
+    /**
+     *
+     * Creates a URI {@link RyaType} object.
+     * @param value the {@link URI} object.
+     * @return the {@link RyaType} with the data type set to
+     * {@link XMLSchema#ANYURI} and the data set to the specified {@code value}.
+     */
+    public static RyaType uriRyaType(final URI value) {
+        return new RyaType(XMLSchema.ANYURI, value.stringValue());
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/2e71ff2a/extras/indexing/pom.xml
----------------------------------------------------------------------
diff --git a/extras/indexing/pom.xml b/extras/indexing/pom.xml
index e38e75d..755646c 100644
--- a/extras/indexing/pom.xml
+++ b/extras/indexing/pom.xml
@@ -72,6 +72,11 @@
 			<artifactId>commons-codec</artifactId>
 		</dependency>
 
+		<dependency>
+			<groupId>org.apache.httpcomponents</groupId>
+			<artifactId>httpclient</artifactId>
+		</dependency>
+
 
 		<!-- PCJ Indexing -->
 		<dependency>

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/2e71ff2a/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
index 3eb4c39..a90e469 100644
--- 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
@@ -29,8 +29,12 @@ import java.util.Objects;
 import java.util.Optional;
 
 import org.apache.http.annotation.Immutable;
+import org.apache.log4j.Logger;
 import org.apache.rya.api.domain.RyaURI;
 import org.apache.rya.indexing.entity.storage.EntityStorage;
+import org.apache.rya.indexing.smarturi.SmartUriAdapter;
+import org.apache.rya.indexing.smarturi.SmartUriException;
+import org.openrdf.model.URI;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
@@ -73,6 +77,7 @@ import edu.umd.cs.findbugs.annotations.Nullable;
 @Immutable
 @DefaultAnnotation(NonNull.class)
 public class Entity {
+    private static final Logger log = Logger.getLogger(Entity.class);
 
     private final RyaURI subject;
     private final ImmutableList<RyaURI> explicitTypeIds;
@@ -84,18 +89,60 @@ public class Entity {
 
     private final int version;
 
+    private URI smartUri = null;
+
     /**
-     * To construct an instances of this class, use {@link Builder}.
+     * To construct an instance of this class, use {@link Builder}.
+     * @param subject Identifies the thing that is being represented as an
+     * Entity.
+     * @param explicitTypeIds {@link Type}s that have been explicitly applied to
+     * the {@link Entity}.
+     * @param typeProperties All {@link Property}s that have been set for the
+     * Entity, grouped by Type ID.
+     * @param version The version of this Entity. This value is used by the
+     * {@link EntityStorage} to prevent stale updates.
+     * @param smartUri the Smart {@link URI} representation of this
+     * {@link Entity}.
      */
     private Entity(
             final RyaURI subject,
             final ImmutableList<RyaURI> explicitTypeIds,
             final ImmutableMap<RyaURI, ImmutableMap<RyaURI, Property>> typeProperties,
-            final int version) {
+            final int version,
+            final URI smartUri) {
         this.subject = requireNonNull(subject);
         this.explicitTypeIds = requireNonNull(explicitTypeIds);
         properties = requireNonNull(typeProperties);
         this.version = version;
+        if (smartUri != null) {
+            this.smartUri = smartUri;
+        } else {
+            // if Smart URI isn't provided create it from the given properties
+            try {
+                this.smartUri = SmartUriAdapter.serializeUriEntity(this);
+            } catch (final SmartUriException e) {
+                log.error("Unable to create a Smart URI for the entity", e);
+            }
+        }
+    }
+
+    /**
+     * To construct an instance of this class, use {@link Builder}.
+     * @param subject Identifies the thing that is being represented as an
+     * Entity.
+     * @param explicitTypeIds {@link Type}s that have been explicitly applied to
+     * the {@link Entity}.
+     * @param typeProperties All {@link Property}s that have been set for the
+     * Entity, grouped by Type ID.
+     * @param version The version of this Entity. This value is used by the
+     * {@link EntityStorage} to prevent stale updates.
+     */
+    private Entity(
+            final RyaURI subject,
+            final ImmutableList<RyaURI> explicitTypeIds,
+            final ImmutableMap<RyaURI, ImmutableMap<RyaURI, Property>> typeProperties,
+            final int version) {
+        this(subject, explicitTypeIds, typeProperties, version, null);
     }
 
     /**
@@ -127,6 +174,45 @@ public class Entity {
         return version;
     }
 
+    /**
+     * @return the Smart {@link URI} representation of this {@link Entity}.
+     */
+    public URI getSmartUri() {
+        return smartUri;
+    }
+
+    /**
+     * Does a lookup to see if the {@link Entity} contains the specified
+     * property for the specified type.
+     * @param typeRyaUri the type {@link RyaURI}. (not {@code null})
+     * @param propertyRyaUri the property {@link RyaURI}. (not {@code null})
+     * @return the {@link Property} or an empty {@link Optional} if it could not
+     * be found in the {@link Entity}.
+     */
+    public Optional<Property> lookupTypeProperty(final Type type, final RyaURI propertyRyaUri) {
+        requireNonNull(type);
+        return lookupTypeProperty(type.getId(), propertyRyaUri);
+    }
+
+    /**
+     * Does a lookup to see if the {@link Entity} contains the specified
+     * property for the specified type.
+     * @param typeRyaUri the type {@link RyaURI}. (not {@code null})
+     * @param propertyRyaUri the property {@link RyaURI}. (not {@code null})
+     * @return the {@link Property} or an empty {@link Optional} if it could not
+     * be found in the {@link Entity}.
+     */
+    public Optional<Property> lookupTypeProperty(final RyaURI typeRyaUri, final RyaURI propertyRyaUri) {
+        requireNonNull(typeRyaUri);
+        requireNonNull(propertyRyaUri);
+        final ImmutableMap<RyaURI, Property> typePropertyMap = properties.get(typeRyaUri);
+        Optional<Property> property = Optional.empty();
+        if (typePropertyMap != null) {
+            property = Optional.of(typePropertyMap.get(propertyRyaUri));
+        }
+        return property;
+    }
+
     @Override
     public int hashCode() {
         return Objects.hash(subject, explicitTypeIds, properties, version);
@@ -206,6 +292,7 @@ public class Entity {
         private RyaURI subject = null;
         private final List<RyaURI> explicitTypes = new ArrayList<>();
         private final Map<RyaURI, Map<RyaURI, Property>> properties = new HashMap<>();
+        private URI smartUri = null;
 
         private int version = 0;
 
@@ -230,6 +317,8 @@ public class Entity {
             }
 
             version = entity.getVersion();
+
+            smartUri = entity.getSmartUri();
         }
 
         /**
@@ -303,6 +392,27 @@ public class Entity {
         }
 
         /**
+         * @param smartUri - the Smart {@link URI} representation of this
+         * {@link Entity}.
+         * @return This {@link Builder} so that method invocations may be chained.
+         */
+        public Builder setSmartUri(final URI smartUri) {
+            this.smartUri = smartUri;
+            return this;
+        }
+
+        /**
+         * Indicates that the builder should rebuild the Smart URI. This should
+         * be used when properties or anything else in the {@link Entity} has
+         * changed.
+         * @return This {@link Builder} so that method invocations may be chained.
+         */
+        public Builder rebuildSmartUri() {
+            setSmartUri(null);
+            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.
@@ -324,7 +434,8 @@ public class Entity {
             return new Entity(subject,
                     ImmutableList.copyOf( explicitTypes ),
                     propertiesBuilder.build(),
-                    version);
+                    version,
+                    smartUri);
         }
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/2e71ff2a/extras/indexing/src/main/java/org/apache/rya/indexing/entity/storage/mongo/EntityDocumentConverter.java
----------------------------------------------------------------------
diff --git a/extras/indexing/src/main/java/org/apache/rya/indexing/entity/storage/mongo/EntityDocumentConverter.java b/extras/indexing/src/main/java/org/apache/rya/indexing/entity/storage/mongo/EntityDocumentConverter.java
index a46fd5a..f2647ef 100644
--- a/extras/indexing/src/main/java/org/apache/rya/indexing/entity/storage/mongo/EntityDocumentConverter.java
+++ b/extras/indexing/src/main/java/org/apache/rya/indexing/entity/storage/mongo/EntityDocumentConverter.java
@@ -27,7 +27,9 @@ import org.apache.rya.api.domain.RyaType;
 import org.apache.rya.api.domain.RyaURI;
 import org.apache.rya.indexing.entity.model.Entity;
 import org.apache.rya.indexing.entity.model.Property;
+import org.apache.rya.indexing.entity.storage.mongo.key.MongoDbSafeKey;
 import org.bson.Document;
+import org.openrdf.model.impl.URIImpl;
 
 import edu.umd.cs.findbugs.annotations.DefaultAnnotation;
 import edu.umd.cs.findbugs.annotations.NonNull;
@@ -42,6 +44,7 @@ public class EntityDocumentConverter implements DocumentConverter<Entity> {
     public static final String EXPLICIT_TYPE_IDS = "explicitTypeIds";
     public static final String PROPERTIES = "properties";
     public static final String VERSION = "version";
+    public static final String SMART_URI = "smartUri";
 
     private final RyaTypeDocumentConverter ryaTypeConverter = new RyaTypeDocumentConverter();
 
@@ -62,8 +65,9 @@ public class EntityDocumentConverter implements DocumentConverter<Entity> {
             entity.getProperties().get(typeId)
                 .forEach((propertyNameUri, property) -> {
                     final String propertyName = property.getName().getData();
+                    final String encodedPropertyName = MongoDbSafeKey.encodeKey(propertyName);
                     final RyaType value = property.getValue();
-                    typePropertiesDoc.append(propertyName,  ryaTypeConverter.toDocument(value));
+                    typePropertiesDoc.append(encodedPropertyName,  ryaTypeConverter.toDocument(value));
                 });
             propertiesDoc.append(typeId.getData(), typePropertiesDoc);
         }
@@ -71,6 +75,8 @@ public class EntityDocumentConverter implements DocumentConverter<Entity> {
 
         doc.append(VERSION, entity.getVersion());
 
+        doc.append(SMART_URI, entity.getSmartUri().stringValue());
+
         return doc;
     }
 
@@ -99,6 +105,11 @@ public class EntityDocumentConverter implements DocumentConverter<Entity> {
                     "' because its '" + VERSION + "' field is missing.");
         }
 
+        if(!document.containsKey(SMART_URI)) {
+            throw new DocumentConverterException("Could not convert document '" + document +
+                    "' because its '" + SMART_URI + "' field is missing.");
+        }
+
         // Perform the conversion.
         final Entity.Builder builder = Entity.builder()
                 .setSubject( new RyaURI(document.getString(SUBJECT)) );
@@ -110,14 +121,17 @@ public class EntityDocumentConverter implements DocumentConverter<Entity> {
         for(final String typeId : propertiesDoc.keySet()) {
             final Document typePropertiesDoc = (Document) propertiesDoc.get(typeId);
             for(final String propertyName : typePropertiesDoc.keySet()) {
+                final String decodedPropertyName = MongoDbSafeKey.decodeKey(propertyName);
                 final Document value = (Document) typePropertiesDoc.get(propertyName);
                 final RyaType propertyValue = ryaTypeConverter.fromDocument( value );
-                builder.setProperty(new RyaURI(typeId), new Property(new RyaURI(propertyName), propertyValue));
+                builder.setProperty(new RyaURI(typeId), new Property(new RyaURI(decodedPropertyName), propertyValue));
             }
         }
 
         builder.setVersion( document.getInteger(VERSION) );
 
+        builder.setSmartUri( new URIImpl(document.getString(SMART_URI)) );
+
         return builder.build();
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/2e71ff2a/extras/indexing/src/main/java/org/apache/rya/indexing/entity/storage/mongo/MongoEntityStorage.java
----------------------------------------------------------------------
diff --git a/extras/indexing/src/main/java/org/apache/rya/indexing/entity/storage/mongo/MongoEntityStorage.java b/extras/indexing/src/main/java/org/apache/rya/indexing/entity/storage/mongo/MongoEntityStorage.java
index 3fc817b..1b4681d 100644
--- a/extras/indexing/src/main/java/org/apache/rya/indexing/entity/storage/mongo/MongoEntityStorage.java
+++ b/extras/indexing/src/main/java/org/apache/rya/indexing/entity/storage/mongo/MongoEntityStorage.java
@@ -34,6 +34,7 @@ import org.apache.rya.indexing.entity.model.TypedEntity;
 import org.apache.rya.indexing.entity.storage.EntityStorage;
 import org.apache.rya.indexing.entity.storage.mongo.ConvertingCursor.Converter;
 import org.apache.rya.indexing.entity.storage.mongo.DocumentConverter.DocumentConverterException;
+import org.apache.rya.indexing.entity.storage.mongo.key.MongoDbSafeKey;
 import org.bson.Document;
 import org.bson.conversions.Bson;
 
@@ -225,16 +226,17 @@ public class MongoEntityStorage implements EntityStorage {
 
     private static Stream<Bson> makePropertyFilters(final RyaURI typeId, final Property property) {
         final String propertyName = property.getName().getData();
+        final String encodedPropertyName = MongoDbSafeKey.encodeKey(propertyName);
 
         // Must match the property's data type.
         final String dataTypePath = Joiner.on(".").join(
-                new String[]{EntityDocumentConverter.PROPERTIES, typeId.getData(), propertyName, RyaTypeDocumentConverter.DATA_TYPE});
+                new String[]{EntityDocumentConverter.PROPERTIES, typeId.getData(), encodedPropertyName, RyaTypeDocumentConverter.DATA_TYPE});
         final String propertyDataType = property.getValue().getDataType().stringValue();
         final Bson dataTypeFilter = Filters.eq(dataTypePath, propertyDataType);
 
         // Must match the property's value.
         final String valuePath = Joiner.on(".").join(
-                new String[]{EntityDocumentConverter.PROPERTIES, typeId.getData(), propertyName, RyaTypeDocumentConverter.VALUE});
+                new String[]{EntityDocumentConverter.PROPERTIES, typeId.getData(), encodedPropertyName, RyaTypeDocumentConverter.VALUE});
         final String propertyValue = property.getValue().getData();
         final Bson valueFilter = Filters.eq(valuePath, propertyValue);
 

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/2e71ff2a/extras/indexing/src/main/java/org/apache/rya/indexing/entity/storage/mongo/key/MongoDbSafeKey.java
----------------------------------------------------------------------
diff --git a/extras/indexing/src/main/java/org/apache/rya/indexing/entity/storage/mongo/key/MongoDbSafeKey.java b/extras/indexing/src/main/java/org/apache/rya/indexing/entity/storage/mongo/key/MongoDbSafeKey.java
new file mode 100644
index 0000000..3d569f9
--- /dev/null
+++ b/extras/indexing/src/main/java/org/apache/rya/indexing/entity/storage/mongo/key/MongoDbSafeKey.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 org.apache.rya.indexing.entity.storage.mongo.key;
+
+import org.javatuples.Pair;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+/**
+ * Utilities to escape keys to be safe for MongoDB use.
+ */
+public final class MongoDbSafeKey {
+    /**
+     * Encode characters in this order.
+     */
+    private static final ImmutableList<Pair<String, String>> ESCAPE_CHARACTERS = ImmutableList.of(
+            new Pair<>("\\", "\\\\"),
+            new Pair<>("\\$", "\\u0024"),
+            new Pair<>(".", "\\u002e")
+        );
+
+    /**
+     * Decode characters in this order (reverse order of encoding).
+     */
+    private static final ImmutableList<Pair<String, String>> UNESCAPE_CHARACTERS = ImmutableList.copyOf(Lists.reverse(ESCAPE_CHARACTERS));
+
+    /**
+     * Private constructor to prevent instantiation.
+     */
+    private MongoDbSafeKey() {
+    }
+
+    /**
+     * Encodes a string to be safe for use as a MongoDB field name.
+     * @param key the unencoded key.
+     * @return the encoded key.
+     */
+    public static String encodeKey(final String key) {
+        String encodedKey = key;
+        for (final Pair<String, String> pair : ESCAPE_CHARACTERS) {
+            final String unescapedCharacter = pair.getValue0();
+            final String escapedCharacter = pair.getValue1();
+            encodedKey = encodedKey.replace(unescapedCharacter, escapedCharacter);
+        }
+
+        return encodedKey;
+    }
+
+    /**
+     * Decodes a MongoDB safe field name to an unencoded string.
+     * @param key the encoded key.
+     * @return the unencoded key.
+     */
+    public static String decodeKey(final String key) {
+        String decodedKey = key;
+        for (final Pair<String, String> pair : UNESCAPE_CHARACTERS) {
+            final String unescapedCharacter = pair.getValue0();
+            final String escapedCharacter = pair.getValue1();
+            decodedKey = decodedKey.replace(escapedCharacter, unescapedCharacter);
+        }
+
+        return decodedKey;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/2e71ff2a/extras/indexing/src/main/java/org/apache/rya/indexing/mongodb/MongoDbSmartUri.java
----------------------------------------------------------------------
diff --git a/extras/indexing/src/main/java/org/apache/rya/indexing/mongodb/MongoDbSmartUri.java b/extras/indexing/src/main/java/org/apache/rya/indexing/mongodb/MongoDbSmartUri.java
new file mode 100644
index 0000000..9fdfad6
--- /dev/null
+++ b/extras/indexing/src/main/java/org/apache/rya/indexing/mongodb/MongoDbSmartUri.java
@@ -0,0 +1,172 @@
+/*
+ * 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.mongodb;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.net.UnknownHostException;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.rya.api.domain.RyaURI;
+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 org.apache.rya.indexing.entity.storage.EntityStorage;
+import org.apache.rya.indexing.entity.storage.EntityStorage.EntityStorageException;
+import org.apache.rya.indexing.entity.storage.mongo.ConvertingCursor;
+import org.apache.rya.indexing.entity.storage.mongo.MongoEntityStorage;
+import org.apache.rya.indexing.smarturi.SmartUriAdapter;
+import org.apache.rya.indexing.smarturi.SmartUriException;
+import org.apache.rya.indexing.smarturi.SmartUriStorage;
+import org.apache.rya.mongodb.MongoConnectorFactory;
+import org.apache.rya.mongodb.MongoDBRdfConfiguration;
+import org.openrdf.model.URI;
+import org.openrdf.model.Value;
+
+import com.mongodb.MongoClient;
+import com.mongodb.MongoException;
+
+/**
+ * MongoDB implementation of the Smart URI.
+ */
+public class MongoDbSmartUri implements SmartUriStorage {
+    private boolean isInit = false;
+    private final MongoDBRdfConfiguration conf;
+    private MongoClient mongoClient = null;
+    private EntityStorage entityStorage;
+
+    /**
+     * Creates a new instance of {@link MongoDbSmartUri}.
+     * @param conf the {@link MongoDBRdfConfiguration}. (not {@code null})
+     */
+    public MongoDbSmartUri(final MongoDBRdfConfiguration conf) {
+        this.conf = checkNotNull(conf);
+    }
+
+    @Override
+    public void storeEntity(final RyaURI subject, final Map<URI, Value> map) throws SmartUriException {
+        checkInit();
+
+        final URI uri = SmartUriAdapter.serializeUri(subject, map);
+        final Entity entity = SmartUriAdapter.deserializeUriEntity(uri);
+
+        // Create it.
+        try {
+            entityStorage.create(entity);
+        } catch (final EntityStorageException e) {
+            throw new SmartUriException("Failed to create entity storage", e);
+        }
+    }
+
+    @Override
+    public void storeEntity(final Entity entity) throws SmartUriException {
+        checkInit();
+
+        // Create it.
+        try {
+            entityStorage.create(entity);
+        } catch (final EntityStorageException e) {
+            throw new SmartUriException("Failed to create entity storage", e);
+        }
+    }
+
+    @Override
+    public void updateEntity(final Entity oldEntity, final Entity updatedEntity) throws SmartUriException {
+        checkInit();
+
+        // Update it.
+        try {
+            entityStorage.update(oldEntity, updatedEntity);
+        } catch (final EntityStorageException e) {
+            throw new SmartUriException("Failed to update entity", e);
+        }
+    }
+
+    @Override
+    public Entity queryEntity(final RyaURI subject) throws SmartUriException {
+        checkInit();
+
+        // Query it.
+        try {
+            final Optional<Entity> resultEntity = entityStorage.get(subject);
+            return resultEntity.get();
+        } catch (final EntityStorageException e) {
+            throw new SmartUriException("Failed to query entity storage", e);
+        }
+    }
+
+    @Override
+    public ConvertingCursor<TypedEntity> queryEntity(final Type type, final Map<URI, Value> map) throws SmartUriException {
+        checkInit();
+
+        // Query it.
+        try {
+            final Set<Property> properties = SmartUriAdapter.mapToProperties(map);
+            final ConvertingCursor<TypedEntity> cursor = entityStorage.search(Optional.empty(), type, properties);
+            return cursor;
+        } catch (final EntityStorageException e) {
+            throw new SmartUriException("Failed to query entity storage", e);
+        }
+    }
+
+    private void checkInit() throws SmartUriException {
+        if (!isInit) {
+            try {
+                setupClient(conf);
+            } catch (final UnknownHostException | MongoException e) {
+                throw new SmartUriException("Failed to setup MongoDB client", e);
+            }
+        }
+    }
+
+    /**
+     * Setup the MongoDB client.
+     * @param conf the {@link Configuration}.
+     * @throws UnknownHostException
+     * @throws MongoException
+     */
+    private void setupClient(final Configuration conf) throws UnknownHostException, MongoException {
+        final MongoDBRdfConfiguration mongoConf = (MongoDBRdfConfiguration) conf;
+        mongoClient = mongoConf.getMongoClient();
+        if (mongoClient == null) {
+            mongoClient = MongoConnectorFactory.getMongoClient(conf);
+        }
+        entityStorage = new MongoEntityStorage(mongoClient, mongoConf.getMongoInstance());
+        isInit = true;
+    }
+
+    /**
+     * Shutdown the MongoDB client.
+     */
+    public void shutdown() {
+        IOUtils.closeQuietly(mongoClient);
+    }
+
+    /**
+     * @return the {@link EntityStorage}.
+     */
+    public EntityStorage getEntityStorage() {
+        return entityStorage;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/2e71ff2a/extras/indexing/src/main/java/org/apache/rya/indexing/smarturi/SmartUriAdapter.java
----------------------------------------------------------------------
diff --git a/extras/indexing/src/main/java/org/apache/rya/indexing/smarturi/SmartUriAdapter.java b/extras/indexing/src/main/java/org/apache/rya/indexing/smarturi/SmartUriAdapter.java
new file mode 100644
index 0000000..d6a5e8a
--- /dev/null
+++ b/extras/indexing/src/main/java/org/apache/rya/indexing/smarturi/SmartUriAdapter.java
@@ -0,0 +1,688 @@
+/*
+ * 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.smarturi;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URISyntaxException;
+import java.net.URLDecoder;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.utils.URIBuilder;
+import org.apache.http.client.utils.URLEncodedUtils;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.rya.api.domain.RyaType;
+import org.apache.rya.api.domain.RyaURI;
+import org.apache.rya.api.resolver.RdfToRyaConversions;
+import org.apache.rya.api.resolver.RyaToRdfConversions;
+import org.apache.rya.indexing.entity.model.Entity;
+import org.apache.rya.indexing.entity.model.Property;
+import org.joda.time.DateTime;
+import org.joda.time.format.ISODateTimeFormat;
+import org.openrdf.model.URI;
+import org.openrdf.model.Value;
+import org.openrdf.model.impl.URIImpl;
+import org.openrdf.model.vocabulary.XMLSchema;
+
+import com.google.common.base.Charsets;
+import com.google.common.collect.HashBiMap;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.primitives.Doubles;
+import com.google.common.primitives.Floats;
+import com.google.common.primitives.Ints;
+import com.google.common.primitives.Longs;
+
+/**
+ * Interface for serializing and deserializing Smart URIs.
+ */
+public class SmartUriAdapter {
+    private static final String ENTITY_TYPE_MAP_URN = "urn://entityTypeMap";
+    private static final URI RYA_TYPES_URI = new URIImpl("urn://ryaTypes");
+
+    /**
+     * Private constructor to prevent instantiation.
+     */
+    private SmartUriAdapter() {
+    }
+
+    private static URI createTypePropertiesUri(final ImmutableMap<RyaURI, ImmutableMap<RyaURI, Property>> typeProperties) throws SmartUriException {
+        final List<NameValuePair> nameValuePairs = new ArrayList<>();
+        for (final Entry<RyaURI, ImmutableMap<RyaURI, Property>> typeProperty : typeProperties.entrySet()) {
+            final RyaURI type = typeProperty.getKey();
+            final Map<RyaURI, Property> propertyMap = typeProperty.getValue();
+            final URI typeUri = createIndividualTypeWithPropertiesUri(type, propertyMap);
+            final String keyString = type.getDataType().getLocalName();
+            final String valueString = typeUri.getLocalName();
+            nameValuePairs.add(new BasicNameValuePair(keyString, valueString));
+        }
+
+        final URIBuilder uriBuilder = new URIBuilder();
+        uriBuilder.addParameters(nameValuePairs);
+
+        String uriString;
+        try {
+            final java.net.URI uri = uriBuilder.build();
+            final String queryString = uri.getRawSchemeSpecificPart();
+            uriString = "urn:test" + queryString;
+        } catch (final URISyntaxException e) {
+            throw new SmartUriException("Unable to create type properties for the Smart URI", e);
+        }
+
+        return new URIImpl(uriString);
+    }
+
+    private static String getShortNameForType(final RyaURI type) throws SmartUriException {
+        String typeUriString;
+        try {
+            typeUriString = new java.net.URI(type.getData()).getRawSchemeSpecificPart();
+        } catch (final URISyntaxException e) {
+            throw new SmartUriException("Unable to get create URI for type", e);
+        }
+        final Path path = Paths.get(typeUriString);
+        final String shortName = path.getFileName().toString();
+        return shortName;
+    }
+
+
+    private static String addTypePrefixToUri(final String uriString, final String typePrefix) {
+        int location = StringUtils.lastIndexOf(uriString, "#");
+        if (location == - 1) {
+            location = StringUtils.lastIndexOf(uriString, "/");
+        }
+
+        final String lastSegment = uriString.substring(location + 1);
+
+        final String formattedUriString = uriString.substring(0, location + 1) + typePrefix + lastSegment;
+        return formattedUriString;
+    }
+
+    private static String removeTypePrefixFromUri(final String uriString, final String typePrefix) {
+        int location = StringUtils.lastIndexOf(uriString, "#");
+        if (location == - 1) {
+            location = StringUtils.lastIndexOf(uriString, "/");
+        }
+
+        final String lastSegment = uriString.substring(location + 1);
+        final String replacement = lastSegment.replaceFirst(typePrefix + ".", "");
+
+        final String formattedUriString = uriString.substring(0, location + 1) + replacement;
+        return formattedUriString;
+    }
+
+    private static Map<RyaURI, String> createTypeMap(final List<RyaURI> types) throws SmartUriException {
+        final Map<RyaURI, String> map = new LinkedHashMap<>();
+        for (final RyaURI type : types) {
+            final String shortName = getShortNameForType(type);
+            map.put(type, shortName);
+        }
+        return map;
+    }
+
+    private static URI createTypeMapUri(final List<RyaURI> types) throws SmartUriException {
+        final List<NameValuePair> nameValuePairs = new ArrayList<>();
+        for (final RyaURI type : types) {
+            final String shortName = getShortNameForType(type);
+            nameValuePairs.add(new BasicNameValuePair(type.getData(), shortName));
+        }
+
+        final URIBuilder uriBuilder = new URIBuilder();
+        uriBuilder.addParameters(nameValuePairs);
+
+        String uriString;
+        try {
+            final java.net.URI uri = uriBuilder.build();
+            final String queryString = uri.getRawSchemeSpecificPart();
+            uriString = ENTITY_TYPE_MAP_URN + queryString;
+        } catch (final URISyntaxException e) {
+            throw new SmartUriException("Unable to create type properties for the Smart URI", e);
+        }
+
+        return new URIImpl(uriString);
+    }
+
+    private static Map<RyaURI, String> convertUriToTypeMap(final URI typeMapUri) throws SmartUriException {
+        final Map<RyaURI, String> map = new HashMap<>();
+        java.net.URI uri;
+        try {
+            final URIBuilder uriBuilder = new URIBuilder(typeMapUri.stringValue());
+            uri = uriBuilder.build();
+        } catch (final URISyntaxException e) {
+            throw new SmartUriException("Unable to parse Rya type map in Smart URI", e);
+        }
+
+        final List<NameValuePair> params = URLEncodedUtils.parse(uri, Charsets.UTF_8.name());
+
+        for (final NameValuePair param : params) {
+            final String name = param.getName();
+            final String value = param.getValue();
+            final RyaURI type = new RyaURI(name);
+            map.put(type, value);
+        }
+        return map;
+    }
+
+    private static URI createIndividualTypeWithPropertiesUri(final RyaURI type, final Map<RyaURI, Property> map) throws SmartUriException {
+        final List<NameValuePair> nameValuePairs = new ArrayList<>();
+        for (final Entry<RyaURI, Property> entry : map.entrySet()) {
+            final RyaURI key = entry.getKey();
+            final Property property = entry.getValue();
+
+            final RyaType ryaType = property.getValue();
+            final String keyString = (new URIImpl(key.getData())).getLocalName();
+            final Value value = RyaToRdfConversions.convertValue(ryaType);
+            final String valueString = value.stringValue();
+            nameValuePairs.add(new BasicNameValuePair(keyString, valueString));
+        }
+
+        final URIBuilder uriBuilder = new URIBuilder();
+        uriBuilder.addParameters(nameValuePairs);
+
+        String uriString;
+        try {
+            final java.net.URI uri = uriBuilder.build();
+            final String queryString = uri.getRawSchemeSpecificPart();
+            uriString = type.getData()/*new URIImpl(type.getData()).getLocalName()*/ + queryString;
+        } catch (final URISyntaxException e) {
+            throw new SmartUriException("Unable to create type URI with all its properties for the Smart URI", e);
+        }
+
+        return new URIImpl(uriString);
+    }
+
+    private static Entity convertMapToEntity(final RyaURI subject, final Map<RyaURI, Map<URI, Value>> map) {
+        final Entity.Builder entityBuilder = Entity.builder();
+        entityBuilder.setSubject(subject);
+
+        for (final Entry<RyaURI, Map<URI, Value>> typeEntry : map.entrySet()) {
+            final RyaURI type = typeEntry.getKey();
+            final Map<URI, Value> subMap = typeEntry.getValue();
+            entityBuilder.setExplicitType(type);
+            for (final Entry<URI, Value> entry : subMap.entrySet()) {
+                final URI uri = entry.getKey();
+                final Value value = entry.getValue();
+                final RyaURI ryaUri = new RyaURI(uri.stringValue());
+                final RyaURI ryaName = new RyaURI(uri.stringValue());
+                final RyaType ryaType = new RyaType(value.stringValue());
+                final Property property = new Property(ryaName, ryaType);
+                entityBuilder.setProperty(ryaUri, property);
+            }
+        }
+        final Entity entity = entityBuilder.build();
+        return entity;
+    }
+
+    public static RyaURI findSubject(final URI uri) throws SmartUriException {
+        final String uriString = uri.stringValue();
+        return findSubject(uriString);
+    }
+
+    public static RyaURI findSubject(final String uriString) throws SmartUriException {
+        java.net.URI uri;
+        try {
+            uri = new java.net.URI(uriString);
+        } catch (final URISyntaxException e) {
+            throw new SmartUriException("Could not find subject in Smart URI", e);
+        }
+        final RyaURI subject;
+        final String fullFragment = uri.getFragment();
+        if (fullFragment != null) {
+            final int queryPosition = fullFragment.indexOf("?");
+            String partialFragment = null;
+            if (queryPosition != - 1) {
+                partialFragment = fullFragment.substring(0, queryPosition);
+            }
+            final String subjectString = uri.getScheme() + ":" + uri.getSchemeSpecificPart() + "#" + partialFragment;
+            subject = new RyaURI(subjectString);
+        } else {
+            final int queryPosition = uriString.indexOf("?");
+            String subjectString = null;
+            if (queryPosition != - 1) {
+                subjectString = uriString.substring(0, queryPosition);
+            } else {
+                subjectString = uriString;
+            }
+            subject = new RyaURI(subjectString);
+        }
+
+        return subject;
+    }
+
+
+    /**
+     * Serializes an {@link Entity} into a Smart {@link URI}.
+     * @param entity the {@link Entity} to serialize into a Smart URI.
+     * @return the Smart {@link URI}.
+     * @throws SmartUriException
+     */
+    public static URI serializeUriEntity(final Entity entity) throws SmartUriException {
+        final Map<URI, Value> objectMap = new LinkedHashMap<>();
+
+        // Adds the entity's types to the Smart URI
+        final List<RyaURI> typeIds = entity.getExplicitTypeIds();
+        final Map<RyaURI, String> ryaTypeMap = createTypeMap(typeIds);
+        final URI ryaTypeMapUri = createTypeMapUri(typeIds);
+        final RyaType valueRyaType = new RyaType(XMLSchema.ANYURI, ryaTypeMapUri.stringValue());
+        final Value typeValue = RyaToRdfConversions.convertValue(valueRyaType);
+        objectMap.put(RYA_TYPES_URI, typeValue);
+
+        final RyaURI subject = entity.getSubject();
+        final Map<RyaURI, ImmutableMap<RyaURI, Property>> typeMap = entity.getProperties();
+        for (final Entry<RyaURI, ImmutableMap<RyaURI, Property>> typeEntry : typeMap.entrySet()) {
+            final RyaURI type = typeEntry.getKey();
+            String typeShortName = ryaTypeMap.get(type);
+            typeShortName = typeShortName != null ? typeShortName + "." : "";
+            final ImmutableMap<RyaURI, Property> typeProperties = typeEntry.getValue();
+            for (final Entry<RyaURI, Property> properties : typeProperties.entrySet()) {
+                final RyaURI key = properties.getKey();
+                final Property property = properties.getValue();
+                final String valueString = property.getValue().getData();
+                final RyaType ryaType = property.getValue();
+
+                //final RyaType ryaType = new RyaType(new URIImpl(key.getData()), valueString);
+
+                final Value value = RyaToRdfConversions.convertValue(ryaType);
+
+                String formattedKey = key.getData();
+                if (StringUtils.isNotBlank(typeShortName)) {
+                    formattedKey = addTypePrefixToUri(key.getData(), typeShortName);
+                }
+                final URI uri = new URIImpl(formattedKey);
+                objectMap.put(uri, value);
+            }
+        }
+
+        return serializeUri(subject, objectMap);
+    }
+
+    /**
+     * Serializes a map into a URI.
+     * @param subject the {@link RyaURI} subject of the Entity. Identifies the
+     * thing that is being represented as an Entity.
+     * @param map the {@link Map} of {@link URI}s to {@link Value}s.
+     * @return the Smart {@link URI}.
+     * @throws SmartUriException
+     */
+    public static URI serializeUri(final RyaURI subject, final Map<URI, Value> map) throws SmartUriException {
+        final String subjectData = subject.getData();
+        final int fragmentPosition = subjectData.indexOf("#");
+        String prefix = subjectData;
+        String fragment = null;
+        if (fragmentPosition > -1) {
+            prefix = subjectData.substring(0, fragmentPosition);
+            fragment = subjectData.substring(fragmentPosition + 1, subjectData.length());
+        }
+
+        URIBuilder uriBuilder = null;
+        try {
+            if (fragmentPosition > -1) {
+                uriBuilder = new URIBuilder(new java.net.URI("urn://" + fragment));
+            } else {
+                uriBuilder = new URIBuilder(new java.net.URI(subjectData));
+            }
+        } catch (final URISyntaxException e) {
+            throw new SmartUriException("Unable to serialize a Smart URI from the provided properties", e);
+        }
+        final List<NameValuePair> nameValuePairs = new ArrayList<>();
+
+        for (final Entry<URI, Value> entry : map.entrySet()) {
+            final URI key = entry.getKey();
+            final Value value = entry.getValue();
+            nameValuePairs.add(new BasicNameValuePair(key.getLocalName(), value.stringValue()));
+        }
+
+        uriBuilder.setParameters(nameValuePairs);
+
+        URI uri = null;
+        try {
+            if (fragmentPosition > -1) {
+                final java.net.URI partialUri = uriBuilder.build();
+                final String uriString = StringUtils.removeStart(partialUri.getRawSchemeSpecificPart(), "//");
+                final URIBuilder fragmentUriBuilder = new URIBuilder(new java.net.URI(prefix));
+                fragmentUriBuilder.setFragment(uriString);
+                final String fragmentUriString = fragmentUriBuilder.build().toString();
+                uri = new URIImpl(fragmentUriString);
+            } else {
+                final String uriString = uriBuilder.build().toString();
+                uri = new URIImpl(uriString);
+            }
+        } catch (final URISyntaxException e) {
+            throw new SmartUriException("Smart URI could not serialize the property map.", e);
+        }
+
+        return uri;
+    }
+
+    /**
+     * Deserializes a URI into a map of URI's to values.
+     * @param uri the {@link URI}.
+     * @return the {@link Map} of {@link URI}s to {@link Value}s.
+     * @throws SmartUriException
+     */
+    public static Map<URI, Value> deserializeUri(final URI uri) throws SmartUriException {
+        final String uriString = uri.stringValue();
+        final int fragmentPosition = uriString.indexOf("#");
+        String prefix = uriString.substring(0, fragmentPosition + 1);
+        if (fragmentPosition == -1) {
+            prefix = uriString.split("\\?", 2)[0];
+        }
+        final String fragment = uriString.substring(fragmentPosition + 1, uriString.length());
+        java.net.URI queryUri;
+
+        URIBuilder uriBuilder = null;
+        try {
+             if (fragmentPosition > -1) {
+                 queryUri = new java.net.URI("urn://" + fragment);
+             } else {
+                 queryUri = new java.net.URI(uriString);
+             }
+            uriBuilder = new URIBuilder(queryUri);
+        } catch (final URISyntaxException e) {
+            throw new SmartUriException("Unable to deserialize Smart URI", e);
+        }
+        final Map<URI, Value> map = new HashMap<>();
+        final RyaURI subject = findSubject(uri.stringValue());
+
+        final List<NameValuePair> parameters = uriBuilder.getQueryParams();
+        Map<RyaURI, String> entityTypeMap = new LinkedHashMap<>();
+        Map<String, RyaURI> invertedEntityTypeMap = new LinkedHashMap<>();
+        final Map<RyaURI, Map<URI, Value>> fullMap = new LinkedHashMap<>();
+        for (final NameValuePair pair : parameters) {
+            final String keyString = pair.getName();
+            final String valueString = pair.getValue();
+
+            final URI keyUri = new URIImpl(prefix + keyString);
+            final String decoded;
+            try {
+                decoded = URLDecoder.decode(valueString, Charsets.UTF_8.name());
+            } catch (final UnsupportedEncodingException e) {
+                throw new SmartUriException("", e);
+            }
+            final URI type = TypeDeterminer.determineType(decoded);
+            if (type == XMLSchema.ANYURI) {
+                if (keyString.equals(RYA_TYPES_URI.getLocalName())) {
+                    entityTypeMap = convertUriToTypeMap(new URIImpl(decoded));
+                    invertedEntityTypeMap = HashBiMap.create(entityTypeMap).inverse();
+                }
+            } else {
+                final int keyPrefixLocation = keyString.indexOf(".");
+                final String keyPrefix = keyString.substring(0, keyPrefixLocation);
+                final RyaURI keyCorrespondingType = invertedEntityTypeMap.get(keyPrefix);
+                final String keyName = keyString.substring(keyPrefixLocation + 1, keyString.length());
+                final RyaType ryaType = new RyaType(type, valueString);
+
+                final Value value = RyaToRdfConversions.convertValue(ryaType);
+
+                final String formattedKeyUriString = removeTypePrefixFromUri(keyUri.stringValue(), keyPrefix);
+                final URI formattedKeyUri = new URIImpl(formattedKeyUriString);
+
+                map.put(formattedKeyUri, value);
+            }
+        }
+        return map;
+    }
+
+//    public static Map<URI, Value> deserializeUri(final URI uri) throws SmartUriException {
+//        final String uriString = uri.stringValue();
+//        final int fragmentPosition = uriString.indexOf("#");
+//        String prefix = uriString.substring(0, fragmentPosition + 1);
+//        if (fragmentPosition == -1) {
+//            prefix = uriString.split("\\?", 2)[0];
+//        }
+//        final String fragment = uriString.substring(fragmentPosition + 1, uriString.length());
+//        java.net.URI queryUri;
+//
+//        URIBuilder uriBuilder = null;
+//        try {
+//             if (fragmentPosition > -1) {
+//                 queryUri = new java.net.URI("urn://" + fragment);
+//             } else {
+//                 queryUri = new java.net.URI(uriString);
+//             }
+//            uriBuilder = new URIBuilder(queryUri);
+//        } catch (final URISyntaxException e) {
+//            throw new SmartUriException("Unable to deserialize Smart URI", e);
+//        }
+//        final Map<URI, Value> map = new HashMap<>();
+//        final List<NameValuePair> parameters = uriBuilder.getQueryParams();
+//        Map<RyaURI, String> entityTypeMap = new LinkedHashMap<>();
+//        for (final NameValuePair pair : parameters) {
+//            final String keyString = pair.getName();
+//            final String valueString = pair.getValue();
+//
+//            final URI keyUri = new URIImpl(prefix + keyString);
+//            final URI type = TypeDeterminer.determineType(valueString);
+//            if (type == XMLSchema.ANYURI) {
+//                final String decoded;
+//                try {
+//                    decoded = URLDecoder.decode(valueString, Charsets.UTF_8.name());
+//                } catch (final UnsupportedEncodingException e) {
+//                    throw new SmartUriException("", e);
+//                }
+//                entityTypeMap = convertUriToTypeMap(new URIImpl(decoded));
+//            } else {
+//                final RyaType ryaType = new RyaType(type, valueString);
+//
+//                final Value value = RyaToRdfConversions.convertValue(ryaType);
+//
+//                map.put(keyUri, value);
+//            }
+//        }
+//        return map;
+//    }
+
+    public static Entity deserializeUriEntity(final URI uri) throws SmartUriException {
+        final String uriString = uri.stringValue();
+        final int fragmentPosition = uriString.indexOf("#");
+        String prefix = uriString.substring(0, fragmentPosition + 1);
+        if (fragmentPosition == -1) {
+            prefix = uriString.split("\\?", 2)[0];
+        }
+        final String fragment = uriString.substring(fragmentPosition + 1, uriString.length());
+        java.net.URI queryUri;
+
+        URIBuilder uriBuilder = null;
+        try {
+             if (fragmentPosition > -1) {
+                 queryUri = new java.net.URI("urn://" + fragment);
+             } else {
+                 queryUri = new java.net.URI(uriString);
+             }
+            uriBuilder = new URIBuilder(queryUri);
+        } catch (final URISyntaxException e) {
+            throw new SmartUriException("Unable to deserialize Smart URI", e);
+        }
+
+        final RyaURI subject = findSubject(uri.stringValue());
+
+        final List<NameValuePair> parameters = uriBuilder.getQueryParams();
+        Map<RyaURI, String> entityTypeMap = new LinkedHashMap<>();
+        Map<String, RyaURI> invertedEntityTypeMap = new LinkedHashMap<>();
+        final Map<RyaURI, Map<URI, Value>> fullMap = new LinkedHashMap<>();
+        for (final NameValuePair pair : parameters) {
+            final String keyString = pair.getName();
+            final String valueString = pair.getValue();
+
+            final URI keyUri = new URIImpl(prefix + keyString);
+            final String decoded;
+            try {
+                decoded = URLDecoder.decode(valueString, Charsets.UTF_8.name());
+            } catch (final UnsupportedEncodingException e) {
+                throw new SmartUriException("", e);
+            }
+            final URI type = TypeDeterminer.determineType(decoded);
+            if (type == XMLSchema.ANYURI) {
+                if (keyString.equals(RYA_TYPES_URI.getLocalName())) {
+                    entityTypeMap = convertUriToTypeMap(new URIImpl(decoded));
+                    invertedEntityTypeMap = HashBiMap.create(entityTypeMap).inverse();
+                }
+            } else {
+                final int keyPrefixLocation = keyString.indexOf(".");
+                final String keyPrefix = keyString.substring(0, keyPrefixLocation);
+                final RyaURI keyCorrespondingType = invertedEntityTypeMap.get(keyPrefix);
+                final String keyName = keyString.substring(keyPrefixLocation + 1, keyString.length());
+                final RyaType ryaType = new RyaType(type, valueString);
+
+                final Value value = RyaToRdfConversions.convertValue(ryaType);
+
+                final String formattedKeyUriString = removeTypePrefixFromUri(keyUri.stringValue(), keyPrefix);
+                final URI formattedKeyUri = new URIImpl(formattedKeyUriString);
+                final Map<URI, Value> map = fullMap.get(keyCorrespondingType);
+
+                if (map == null) {
+                    final Map<URI, Value> subMap = new HashMap<>();
+                    subMap.put(formattedKeyUri, value);
+                    fullMap.put(keyCorrespondingType, subMap);
+                } else {
+                    map.put(formattedKeyUri, value);
+                    fullMap.put(keyCorrespondingType, map);
+                }
+            }
+        }
+        final Entity entity = convertMapToEntity(subject, fullMap);
+        return entity;
+    }
+
+    private static final class TypeDeterminer {
+        /**
+         * Private constructor to prevent instantiation.
+         */
+        private TypeDeterminer() {
+        }
+
+        private static URI determineType(final String data) {
+            if (Ints.tryParse(data) != null) {
+                return XMLSchema.INTEGER;
+            } else if (Doubles.tryParse(data) != null) {
+                return XMLSchema.DOUBLE;
+            } else if (Floats.tryParse(data) != null) {
+                return XMLSchema.FLOAT;
+            } else if (isShort(data)) {
+                return XMLSchema.SHORT;
+            } else if (Longs.tryParse(data) != null) {
+                return XMLSchema.LONG;
+            } if (Boolean.parseBoolean(data)) {
+                return XMLSchema.BOOLEAN;
+            } else if (isByte(data)) {
+                return XMLSchema.BYTE;
+            } else if (isDate(data)) {
+                return XMLSchema.DATETIME;
+            } else if (isUri(data)) {
+                return XMLSchema.ANYURI;
+            }
+
+            return XMLSchema.STRING;
+        }
+
+        private static boolean isDate(final String data) {
+            try {
+                DateTime.parse(data, ISODateTimeFormat.dateTimeParser());
+                return true;
+            } catch (final IllegalArgumentException e) {
+                // not a date
+                return false;
+            }
+        }
+
+        private static boolean isShort(final String data) {
+            try {
+                Short.parseShort(data);
+                return true;
+            } catch (final NumberFormatException e) {
+                // not a short
+                return false;
+            }
+        }
+
+        private static boolean isByte(final String data) {
+            try {
+                Byte.parseByte(data);
+                return true;
+            } catch (final NumberFormatException e) {
+                // not a byte
+                return false;
+            }
+        }
+
+        private static boolean isUri(final String data) {
+            try {
+                final String decoded = URLDecoder.decode(data, Charsets.UTF_8.name());
+                new URIImpl(decoded);
+                return true;
+            } catch (final IllegalArgumentException | UnsupportedEncodingException e) {
+                // not a URI
+                return false;
+            }
+        }
+    }
+
+    public static Map<URI, Value> entityToValueMap(final Entity entity) {
+        final Map<URI, Value> map = new LinkedHashMap<>();
+        for (final Entry<RyaURI, ImmutableMap<RyaURI, Property>> entry : entity.getProperties().entrySet()) {
+            for (final Entry<RyaURI, Property> property : entry.getValue().entrySet()) {
+                final RyaURI propertyKey = property.getKey();
+                final URI uri = new URIImpl(propertyKey.getData());
+                final Property propertyValue = property.getValue();
+                final Value value = RyaToRdfConversions.convertValue(propertyValue.getValue());
+                map.put(uri, value);
+            }
+        }
+        return map;
+    }
+
+    /**
+     * Converts a {@link Map} of {@link URI}/{@link Value}s to a {@link Set} of
+     * {@link Property}s.
+     * @param map the {@link Map} of {@link URI}/{@link Value}.
+     * @return the {@link Set} of {@link Property}s.
+     */
+    public static Set<Property> mapToProperties(final Map<URI, Value> map) {
+        final Set<Property> properties = new LinkedHashSet<>();
+        for (final Entry<URI, Value> entry : map.entrySet()) {
+            final URI uri = entry.getKey();
+            final Value value = entry.getValue();
+
+            final RyaURI ryaUri = new RyaURI(uri.stringValue());
+            final RyaType ryaType = RdfToRyaConversions.convertValue(value);
+
+            final Property property = new Property(ryaUri, ryaType);
+            properties.add(property);
+        }
+        return properties;
+    }
+
+    public static Map<URI, Value> propertiesToMap(final Set<Property> properties) {
+        final Map<URI, Value> map = new LinkedHashMap<>();
+        for (final Property property : properties) {
+            final URI uri = new URIImpl(property.getName().getData());
+            final Value value = RyaToRdfConversions.convertValue(property.getValue());
+            map.put(uri, value);
+        }
+        return map;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/2e71ff2a/extras/indexing/src/main/java/org/apache/rya/indexing/smarturi/SmartUriException.java
----------------------------------------------------------------------
diff --git a/extras/indexing/src/main/java/org/apache/rya/indexing/smarturi/SmartUriException.java b/extras/indexing/src/main/java/org/apache/rya/indexing/smarturi/SmartUriException.java
new file mode 100644
index 0000000..979b6b9
--- /dev/null
+++ b/extras/indexing/src/main/java/org/apache/rya/indexing/smarturi/SmartUriException.java
@@ -0,0 +1,36 @@
+/*
+ * 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.smarturi;
+
+/**
+ * Exception thrown when a SmartURI is malformed when attempting to
+ * serialize/deserialize it.
+ */
+public class SmartUriException extends Exception {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Creates a new instance of {@link SmartUriException}.
+     * @param message the message to be displayed by the exception.
+     * @param throwable the source {#link Throwable} cause of the exception.
+     */
+    public SmartUriException(final String message, final Throwable throwable) {
+        super(message, throwable);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/2e71ff2a/extras/indexing/src/main/java/org/apache/rya/indexing/smarturi/SmartUriStorage.java
----------------------------------------------------------------------
diff --git a/extras/indexing/src/main/java/org/apache/rya/indexing/smarturi/SmartUriStorage.java b/extras/indexing/src/main/java/org/apache/rya/indexing/smarturi/SmartUriStorage.java
new file mode 100644
index 0000000..1043d42
--- /dev/null
+++ b/extras/indexing/src/main/java/org/apache/rya/indexing/smarturi/SmartUriStorage.java
@@ -0,0 +1,78 @@
+/*
+ * 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.smarturi;
+
+import java.util.Map;
+
+import org.apache.rya.api.domain.RyaURI;
+import org.apache.rya.indexing.entity.model.Entity;
+import org.apache.rya.indexing.entity.model.Type;
+import org.apache.rya.indexing.entity.model.TypedEntity;
+import org.apache.rya.indexing.entity.storage.mongo.ConvertingCursor;
+import org.calrissian.mango.collect.CloseableIterator;
+import org.openrdf.model.URI;
+import org.openrdf.model.Value;
+
+/**
+ * Interface for interacting with a Smart URI's datastore.
+ */
+public interface SmartUriStorage {
+    /**
+     * Stores the map into the datastore.
+     * @param subject the {@link RyaURI} subject of the Entity. Identifies the
+     * thing that is being represented as an Entity.
+     * @param map the {@link Map} of {@link URI}s to {@link Value}s.
+     * @throws SmartUriException
+     */
+    public void storeEntity(final RyaURI subject, final Map<URI, Value> map) throws SmartUriException;
+
+    /**
+     * Stores the entity into the datastore.
+     * @param entity the {@link Entity}.
+     * @throws SmartUriException
+     */
+    public void storeEntity(final Entity entity) throws SmartUriException;
+
+    /**
+     * Updates the entity.
+     * @param oldEntity the old {@link Entity} to update
+     * @param updatedEntity the new {@link Entity} to replace the old one with.
+     * @throws SmartUriException
+     */
+    public void updateEntity(final Entity oldEntity, final Entity updatedEntity) throws SmartUriException;
+
+    /**
+     * Queries for the entity based on the subject
+     * @param subject the {@link RyaURI} subject of the Entity. Identifies the
+     * thing that is being represented as an Entity.
+     * @return the {@link Entity} matching the subject.
+     * @throws SmartUriException
+     */
+    public Entity queryEntity(final RyaURI subject) throws SmartUriException;
+
+    /**
+     * Queries the datastore for the map.
+     * @param type the type associated with the entity values.
+     * @param map the {@link Map} of {@link URI}s to {@link Value}s.
+     * @return a {@link CloseableIterator} over the {@link TypedEntity}s that
+     * match the search parameters.
+     * @throws SmartUriException
+     */
+   public ConvertingCursor<TypedEntity> queryEntity(final Type type, final Map<URI, Value> map) throws SmartUriException;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/2e71ff2a/extras/indexing/src/test/java/org/apache/rya/indexing/mongo/MongoDbSmartUriTest.java
----------------------------------------------------------------------
diff --git a/extras/indexing/src/test/java/org/apache/rya/indexing/mongo/MongoDbSmartUriTest.java b/extras/indexing/src/test/java/org/apache/rya/indexing/mongo/MongoDbSmartUriTest.java
new file mode 100644
index 0000000..60efbed
--- /dev/null
+++ b/extras/indexing/src/test/java/org/apache/rya/indexing/mongo/MongoDbSmartUriTest.java
@@ -0,0 +1,333 @@
+/*
+ * 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.mongo;
+
+import static org.apache.rya.api.domain.RyaTypeUtils.booleanRyaType;
+import static org.apache.rya.api.domain.RyaTypeUtils.byteRyaType;
+import static org.apache.rya.api.domain.RyaTypeUtils.dateRyaType;
+import static org.apache.rya.api.domain.RyaTypeUtils.doubleRyaType;
+import static org.apache.rya.api.domain.RyaTypeUtils.floatRyaType;
+import static org.apache.rya.api.domain.RyaTypeUtils.intRyaType;
+import static org.apache.rya.api.domain.RyaTypeUtils.longRyaType;
+import static org.apache.rya.api.domain.RyaTypeUtils.shortRyaType;
+import static org.apache.rya.api.domain.RyaTypeUtils.stringRyaType;
+import static org.apache.rya.api.domain.RyaTypeUtils.uriRyaType;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.net.URISyntaxException;
+import java.util.Date;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.rya.api.domain.RyaSchema;
+import org.apache.rya.api.domain.RyaURI;
+import org.apache.rya.api.resolver.RdfToRyaConversions;
+import org.apache.rya.api.resolver.RyaToRdfConversions;
+import org.apache.rya.indexing.accumulo.ConfigUtils;
+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 org.apache.rya.indexing.entity.query.EntityQueryNode;
+import org.apache.rya.indexing.entity.storage.mongo.ConvertingCursor;
+import org.apache.rya.indexing.mongodb.MongoDbSmartUri;
+import org.apache.rya.indexing.smarturi.SmartUriAdapter;
+import org.apache.rya.indexing.smarturi.SmartUriException;
+import org.apache.rya.mongodb.MockMongoFactory;
+import org.apache.rya.mongodb.MongoDBRdfConfiguration;
+import org.joda.time.DateTime;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.openrdf.model.URI;
+import org.openrdf.model.Value;
+import org.openrdf.model.ValueFactory;
+import org.openrdf.model.impl.URIImpl;
+import org.openrdf.model.impl.ValueFactoryImpl;
+import org.openrdf.model.vocabulary.RDF;
+import org.openrdf.query.BindingSet;
+import org.openrdf.query.MalformedQueryException;
+import org.openrdf.query.QueryEvaluationException;
+import org.openrdf.query.algebra.StatementPattern;
+import org.openrdf.query.algebra.evaluation.QueryBindingSet;
+import org.openrdf.query.algebra.helpers.StatementPatternCollector;
+import org.openrdf.query.parser.sparql.SPARQLParser;
+
+import com.beust.jcommander.internal.Lists;
+import com.google.common.collect.ImmutableSet;
+import com.mongodb.MongoClient;
+
+import info.aduna.iteration.CloseableIteration;
+
+/**
+ * Tests for MongoDB based Smart URI.
+ */
+public class MongoDbSmartUriTest {
+    private static final String NAMESPACE = RyaSchema.NAMESPACE;
+    private static final ValueFactory VALUE_FACTORY = ValueFactoryImpl.getInstance();
+
+    // People
+    private static final RyaURI BOB = createRyaUri("Bob");
+
+    // Attributes
+    private static final RyaURI HAS_WEIGHT = createRyaUri("hasWeight");
+    private static final RyaURI HAS_HEIGHT = createRyaUri("hasHeight");
+    private static final RyaURI HAS_SSN = createRyaUri("hasSSN");
+    private static final RyaURI HAS_AGE = createRyaUri("hasAge");
+    private static final RyaURI HAS_INCOME = createRyaUri("hasIncome");
+    private static final RyaURI HAS_NUMBER_OF_CHILDREN = createRyaUri("hasNumberOfChildren");
+    private static final RyaURI HAS_LICENSE_NUMBER = createRyaUri("hasLicenseNumber");
+    private static final RyaURI HAS_EYE_COLOR = createRyaUri("hasEyeColor");
+    private static final RyaURI HAS_HAIR_COLOR = createRyaUri("hasHairColor");
+    private static final RyaURI HAS_DATE_OF_BIRTH = createRyaUri("hasDateOfBirth");
+    private static final RyaURI HAS_EXPIRATION_DATE = createRyaUri("hasExpirationDate");
+    private static final RyaURI HAS_GLASSES = createRyaUri("hasGlasses");
+    private static final RyaURI HAS_EMAIL_ADDRESS = createRyaUri("hasEmailAddress");
+    private static final RyaURI HAS_ATTRIBUTE_SPACE = createRyaUri("has Attribute Space");
+    private static final RyaURI HAS_MOTTO = createRyaUri("hasMotto");
+    private static final RyaURI HAS_BLOOD_TYPE = createRyaUri("hasBloodType");
+    private static final RyaURI HAS_SEX = createRyaUri("hasSex");
+    private static final RyaURI HAS_ADDRESS = createRyaUri("hasAddress");
+    private static final RyaURI HAS_POSITION_TITLE = createRyaUri("hasPositionTitle");
+    private static final RyaURI HAS_WORK_ADDRESS = createRyaUri("hasWorkAddress");
+    private static final RyaURI HAS_EXTENSION = createRyaUri("hasExtension");
+    private static final RyaURI HAS_OFFICE_ROOM_NUMBER = createRyaUri("hasOfficeRoomNumber");
+
+    // Type URIs
+    private static final RyaURI PERSON_TYPE_URI = new RyaURI("urn:example/person");
+    private static final RyaURI EMPLOYEE_TYPE_URI = new RyaURI("urn:example/employee");
+
+    // Entities
+    private static final Entity BOB_ENTITY = createBobEntity();
+
+    // Types
+    private static final Type PERSON_TYPE = createPersonType();
+    private static final Type EMPLOYEE_TYPE = createEmployeeType();
+
+    private static MongoDBRdfConfiguration conf;
+    private static MongoDbSmartUri smartUriConverter;
+
+    @BeforeClass
+    public static void setupClass() throws Exception {
+        conf = new MongoDBRdfConfiguration();
+        conf.set(ConfigUtils.USE_MONGO, "true");
+        conf.set(MongoDBRdfConfiguration.MONGO_DB_NAME, "test");
+        conf.set(MongoDBRdfConfiguration.MONGO_COLLECTION_PREFIX, "rya_");
+        conf.setTablePrefix("another_");
+    }
+
+    @Before
+    public void setupTest() throws Exception {
+        final MongoClient client = MockMongoFactory.newFactory().newMongoClient();
+        conf.setMongoClient(client);
+
+        if (smartUriConverter != null) {
+            smartUriConverter.shutdown();
+        }
+        smartUriConverter = new MongoDbSmartUri(conf);
+    }
+
+    /**
+     * Creates a {@link RyaURI} for the specified local name.
+     * @param localName the URI's local name.
+     * @return the {@link RyraURI}.
+     */
+    private static RyaURI createRyaUri(final String localName) {
+        return createRyaUri(NAMESPACE, localName);
+        //return new RyaURI("http://" + localName);
+    }
+
+    /**
+     * Creates a {@link RyaURI} for the specified local name.
+     * @param namespace the namespace.
+     * @param localName the URI's local name.
+     * @return the {@link RyraURI}.
+     */
+    private static RyaURI createRyaUri(final String namespace, final String localName) {
+        return RdfToRyaConversions.convertURI(VALUE_FACTORY.createURI(namespace, localName));
+    }
+
+    private static Entity createBobEntity() {
+        final Entity bobEntity = Entity.builder()
+            .setSubject(BOB)
+            .setExplicitType(PERSON_TYPE_URI)
+            .setExplicitType(EMPLOYEE_TYPE_URI)
+            .setProperty(PERSON_TYPE_URI, new Property(HAS_WEIGHT, floatRyaType(250.75f)))
+            .setProperty(PERSON_TYPE_URI, new Property(HAS_HEIGHT, doubleRyaType(72.5)))
+            .setProperty(PERSON_TYPE_URI, new Property(HAS_SSN, stringRyaType("123-45-6789")))
+            .setProperty(PERSON_TYPE_URI, new Property(HAS_AGE, shortRyaType((short) 40)))
+            .setProperty(PERSON_TYPE_URI, new Property(HAS_INCOME, intRyaType(50000)))
+            .setProperty(PERSON_TYPE_URI, new Property(HAS_NUMBER_OF_CHILDREN, byteRyaType((byte) 2)))
+            .setProperty(PERSON_TYPE_URI, new Property(HAS_LICENSE_NUMBER, longRyaType(123456789012L)))
+            .setProperty(PERSON_TYPE_URI, new Property(HAS_EYE_COLOR, stringRyaType("blue")))
+            .setProperty(PERSON_TYPE_URI, new Property(HAS_HAIR_COLOR, stringRyaType("brown")))
+            .setProperty(PERSON_TYPE_URI, new Property(HAS_DATE_OF_BIRTH, dateRyaType(new DateTime().minusYears(40))))
+            .setProperty(PERSON_TYPE_URI, new Property(HAS_EXPIRATION_DATE, dateRyaType(new Date())))
+            .setProperty(PERSON_TYPE_URI, new Property(HAS_GLASSES, booleanRyaType(true)))
+            .setProperty(PERSON_TYPE_URI, new Property(HAS_EMAIL_ADDRESS, uriRyaType(new URIImpl("mailto:bob.smitch00@gmail.com"))))
+            .setProperty(PERSON_TYPE_URI, new Property(HAS_ATTRIBUTE_SPACE, stringRyaType("attribute space")))
+            .setProperty(PERSON_TYPE_URI, new Property(HAS_MOTTO, stringRyaType("!@#*\\&%20^ smörgåsbord")))
+            .setProperty(PERSON_TYPE_URI, new Property(HAS_BLOOD_TYPE, stringRyaType("A+ blood type")))
+            .setProperty(PERSON_TYPE_URI, new Property(HAS_SEX, stringRyaType("M")))
+            .setProperty(PERSON_TYPE_URI, new Property(HAS_ADDRESS, stringRyaType("123 Fake St. Washington, DC 20024")))
+            .setProperty(EMPLOYEE_TYPE_URI, new Property(HAS_POSITION_TITLE, stringRyaType("Assistant to the Regional Manager")))
+            .setProperty(EMPLOYEE_TYPE_URI, new Property(HAS_WORK_ADDRESS, stringRyaType("987 Fake Office Rd. Washington, DC 20024")))
+            .setProperty(EMPLOYEE_TYPE_URI, new Property(HAS_EXTENSION, shortRyaType((short) 555)))
+            .setProperty(EMPLOYEE_TYPE_URI, new Property(HAS_OFFICE_ROOM_NUMBER, shortRyaType((short) 9999)))
+            .build();
+
+        return bobEntity;
+    }
+
+    private static Type createPersonType() {
+         final Type personType = new Type(PERSON_TYPE_URI,
+            ImmutableSet.<RyaURI>builder()
+                .add(HAS_WEIGHT)
+                .add(HAS_HEIGHT)
+                .add(HAS_SSN)
+                .add(HAS_AGE)
+                .add(HAS_INCOME)
+                .add(HAS_NUMBER_OF_CHILDREN)
+                .add(HAS_LICENSE_NUMBER)
+                .add(HAS_EYE_COLOR)
+                .add(HAS_HAIR_COLOR)
+                .add(HAS_DATE_OF_BIRTH)
+                .add(HAS_EXPIRATION_DATE)
+                .add(HAS_GLASSES)
+                .add(HAS_EMAIL_ADDRESS)
+                .add(HAS_ATTRIBUTE_SPACE)
+                .add(HAS_MOTTO)
+                .add(HAS_BLOOD_TYPE)
+                .add(HAS_SEX)
+                .add(HAS_ADDRESS)
+                .build());
+         return personType;
+    }
+
+    private static Type createEmployeeType() {
+        final Type employeeType = new Type(EMPLOYEE_TYPE_URI,
+            ImmutableSet.<RyaURI>builder()
+                .add(HAS_POSITION_TITLE)
+                .add(HAS_WORK_ADDRESS)
+                .add(HAS_EXTENSION)
+                .add(HAS_OFFICE_ROOM_NUMBER)
+                .build());
+        return employeeType;
+    }
+
+    private static String getRyaUriLocalName(final RyaURI ryaUri) {
+        return new URIImpl(ryaUri.getData()).getLocalName();
+    }
+
+    @Test
+    public void testSerializeDeserialize() throws SmartUriException, URISyntaxException {
+        final URI smartUri = SmartUriAdapter.serializeUriEntity(BOB_ENTITY);
+        System.out.println(smartUri);
+        final Entity resultEntity = SmartUriAdapter.deserializeUriEntity(smartUri);
+        System.out.println(resultEntity);
+        assertEquals(BOB_ENTITY.getSubject(), resultEntity.getSubject());
+        //assertTrue(Paths.get(BOB_ENTITY.getSubject().getData()).equals(Paths.get(resultEntity.getSubject().getData())));
+    }
+
+    @Test
+    public void testStorage() throws SmartUriException, MalformedQueryException, RuntimeException, QueryEvaluationException {
+        smartUriConverter.storeEntity(BOB_ENTITY);
+
+        final String sparql = "SELECT * WHERE { " +
+            "<" + BOB.getData() + "> <" + RDF.TYPE + "> <" + PERSON_TYPE.getId().getData() + "> . " +
+            "<" + BOB.getData() + "> <" + HAS_SSN.getData() + "> ?ssn . " +
+            "<" + BOB.getData() + "> <" + HAS_AGE.getData() + "> ?age . " +
+            "<" + BOB.getData() + "> <" + HAS_WEIGHT.getData() + "> ?weight . " +
+            "<" + BOB.getData() + "> <" + HAS_ADDRESS.getData() + "> ?address . " +
+        "}";
+
+        final StatementPatternCollector spCollector = new StatementPatternCollector();
+        new SPARQLParser().parseQuery(sparql, null).getTupleExpr().visit(spCollector);
+        final List<StatementPattern> patterns = spCollector.getStatementPatterns();
+        final EntityQueryNode entityQueryNode = new EntityQueryNode(PERSON_TYPE, patterns, smartUriConverter.getEntityStorage());
+        final QueryBindingSet queryBindingSet = new QueryBindingSet();
+        final Property ssnProperty = BOB_ENTITY.lookupTypeProperty(PERSON_TYPE, HAS_SSN).get();
+        queryBindingSet.addBinding(HAS_SSN.getData(), RyaToRdfConversions.convertValue(ssnProperty.getValue()));
+
+        final CloseableIteration<BindingSet, QueryEvaluationException> iter = entityQueryNode.evaluate(queryBindingSet);
+        int count = 0;
+        // These should match what was used in the SPARQL query.
+        final List<String> queryParamNames = Lists.newArrayList("ssn", "age", "weight", "address");
+        while (iter.hasNext()) {
+            final BindingSet bs = iter.next();
+            assertTrue(bs.getBindingNames().containsAll(queryParamNames));
+            count++;
+        }
+        assertEquals(count, 1);
+    }
+
+    @Test
+    public void testUpdate() throws SmartUriException {
+        smartUriConverter.storeEntity(BOB_ENTITY);
+
+        // New properties to add
+        final RyaURI hasNickName = createRyaUri("hasNickName");
+        final RyaURI hasWindowOffice = createRyaUri("hasWindowOffice");
+
+        final Entity.Builder builder = Entity.builder(BOB_ENTITY);
+        builder.setProperty(PERSON_TYPE_URI, new Property(HAS_AGE, shortRyaType((short) 41)));
+        builder.setProperty(PERSON_TYPE_URI, new Property(hasNickName, stringRyaType("Bobby")));
+        builder.setProperty(EMPLOYEE_TYPE_URI, new Property(HAS_POSITION_TITLE, stringRyaType("Assistant Regional Manager")));
+        builder.setProperty(EMPLOYEE_TYPE_URI, new Property(hasWindowOffice, booleanRyaType(true)));
+        builder.setVersion(BOB_ENTITY.getVersion() + 1);
+        builder.rebuildSmartUri();
+
+        final Entity newBobEntity = builder.build();
+
+        smartUriConverter.updateEntity(BOB_ENTITY, newBobEntity);
+
+        final Entity resultEntity = smartUriConverter.queryEntity(BOB_ENTITY.getSubject());
+        assertEquals(newBobEntity.getVersion(), resultEntity.getVersion());
+        assertEquals(newBobEntity.lookupTypeProperty(PERSON_TYPE, HAS_AGE), resultEntity.lookupTypeProperty(PERSON_TYPE, HAS_AGE));
+        assertEquals(newBobEntity.lookupTypeProperty(PERSON_TYPE, hasNickName), resultEntity.lookupTypeProperty(PERSON_TYPE, hasNickName));
+        assertEquals(newBobEntity.lookupTypeProperty(EMPLOYEE_TYPE, HAS_POSITION_TITLE), resultEntity.lookupTypeProperty(EMPLOYEE_TYPE, HAS_POSITION_TITLE));
+        assertEquals(newBobEntity.lookupTypeProperty(EMPLOYEE_TYPE, hasWindowOffice), resultEntity.lookupTypeProperty(EMPLOYEE_TYPE, hasWindowOffice));
+        assertEquals(newBobEntity.getSmartUri(), resultEntity.getSmartUri());
+        final String resultUriString = resultEntity.getSmartUri().stringValue();
+        assertTrue(resultUriString.contains(getRyaUriLocalName(hasWindowOffice)));
+        assertTrue(resultUriString.contains(getRyaUriLocalName(hasNickName)));
+    }
+
+    @Test
+    public void testQuery() throws SmartUriException {
+        smartUriConverter.storeEntity(BOB_ENTITY);
+
+        // Look up Person Type Entities that match Bob's SSN property
+        final Set<Property> properties = new LinkedHashSet<>();
+        properties.add(BOB_ENTITY.lookupTypeProperty(PERSON_TYPE, HAS_SSN).get());
+        final Map<URI, Value> map = SmartUriAdapter.propertiesToMap(properties);
+
+        final ConvertingCursor<TypedEntity> cursor = smartUriConverter.queryEntity(PERSON_TYPE, map);
+        int count = 0;
+        while (cursor.hasNext()) {
+            final TypedEntity typedEntity = cursor.next();
+            System.out.println(typedEntity);
+            count++;
+        }
+        assertEquals(count, 1);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/2e71ff2a/extras/indexingExample/pom.xml
----------------------------------------------------------------------
diff --git a/extras/indexingExample/pom.xml b/extras/indexingExample/pom.xml
index 5304884..50c9a29 100644
--- a/extras/indexingExample/pom.xml
+++ b/extras/indexingExample/pom.xml
@@ -78,6 +78,12 @@ under the License.
             <artifactId>sesame-queryrender</artifactId>
             <version>${openrdf.sesame.version}</version>
         </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/2e71ff2a/extras/rya.merger/pom.xml
----------------------------------------------------------------------
diff --git a/extras/rya.merger/pom.xml b/extras/rya.merger/pom.xml
index 62b799e..44f65ef 100644
--- a/extras/rya.merger/pom.xml
+++ b/extras/rya.merger/pom.xml
@@ -133,11 +133,6 @@ under the License.
          </dependency>
 
         <dependency>
-            <groupId>commons-httpclient</groupId>
-            <artifactId>commons-httpclient</artifactId>
-        </dependency>
-
-        <dependency>
             <groupId>com.beust</groupId>
             <artifactId>jcommander</artifactId>
          </dependency>