You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@atlas.apache.org by su...@apache.org on 2015/12/18 11:44:09 UTC

[09/26] incubator-atlas git commit: ATLAS-47 Entity mutations for complex types (sumasai via shwethags)

ATLAS-47 Entity mutations for complex types (sumasai via shwethags)


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

Branch: refs/heads/branch-0.6-incubating
Commit: 51656991fc008e57936bfc12afa51b9e372ae6a5
Parents: 6c3f096
Author: Shwetha GS <ss...@hortonworks.com>
Authored: Tue Dec 8 12:09:57 2015 +0530
Committer: Shwetha GS <ss...@hortonworks.com>
Committed: Tue Dec 8 12:09:57 2015 +0530

----------------------------------------------------------------------
 .../atlas/hive/bridge/HiveMetaStoreBridge.java  |    9 +-
 .../org/apache/atlas/hive/hook/HiveHookIT.java  |    2 +-
 .../main/java/org/apache/atlas/AtlasClient.java |  141 ++-
 common/pom.xml                                  |   14 +-
 .../org/apache/atlas/ApplicationProperties.java |   86 ++
 .../java/org/apache/atlas/AtlasException.java   |   44 +
 .../atlas/listener/EntityChangeListener.java    |   69 --
 .../atlas/listener/TypesChangeListener.java     |   49 -
 .../java/org/apache/atlas/utils/MD5Utils.java   |   59 +
 .../org/apache/atlas/utils/ParamChecker.java    |  148 +++
 docs/src/site/twiki/Configuration.twiki         |    4 +-
 docs/src/site/twiki/InstallationSteps.twiki     |    2 +-
 notification/pom.xml                            |    5 +
 .../NotificationEntityChangeListener.java       |    4 +-
 pom.xml                                         |    7 +
 release-log.txt                                 |    1 +
 repository/pom.xml                              |    2 +-
 .../apache/atlas/RepositoryMetadataModule.java  |    4 +-
 .../atlas/discovery/DiscoveryException.java     |   74 --
 .../atlas/discovery/DiscoveryService.java       |   52 -
 .../atlas/discovery/HiveLineageService.java     |    4 +-
 .../apache/atlas/discovery/LineageService.java  |   67 --
 .../graph/DefaultGraphPersistenceStrategy.java  |   14 +-
 .../atlas/repository/EntityExistsException.java |   32 -
 .../repository/EntityNotFoundException.java     |   44 -
 .../atlas/repository/MetadataRepository.java    |   38 +-
 .../atlas/repository/graph/EntityProcessor.java |   81 ++
 .../atlas/repository/graph/FullTextMapper.java  |  146 +++
 .../graph/GraphBackedMetadataRepository.java    | 1094 +-----------------
 .../atlas/repository/graph/GraphHelper.java     |  180 ++-
 .../graph/GraphToTypedInstanceMapper.java       |  419 +++++++
 .../graph/TypedInstanceToGraphMapper.java       |  633 ++++++++++
 .../memory/ReplaceIdWithInstance.java           |    1 -
 .../atlas/services/DefaultMetadataService.java  |  168 ++-
 .../apache/atlas/services/MetadataService.java  |  157 ---
 .../query/GraphPersistenceStrategies.scala      |    4 +-
 .../apache/atlas/BaseHiveRepositoryTest.java    |   25 +-
 .../test/java/org/apache/atlas/TestUtils.java   |   29 +-
 .../GraphBackedDiscoveryServiceTest.java        |    4 +-
 .../atlas/discovery/HiveLineageServiceTest.java |    6 +-
 .../GraphBackedMetadataRepositoryTest.java      |   32 +-
 .../graph/GraphRepoMapperScaleTest.java         |   18 +-
 .../service/DefaultMetadataServiceTest.java     |  509 +++++++-
 .../org/apache/atlas/query/GremlinTest.scala    |    1 -
 server-api/pom.xml                              |   53 +
 .../atlas/discovery/DiscoveryException.java     |   74 ++
 .../atlas/discovery/DiscoveryService.java       |   52 +
 .../apache/atlas/discovery/LineageService.java  |   67 ++
 .../atlas/listener/EntityChangeListener.java    |   69 ++
 .../atlas/listener/TypesChangeListener.java     |   49 +
 .../apache/atlas/services/MetadataService.java  |  187 +++
 .../exception/EntityExistsException.java        |   32 +
 .../exception/EntityNotFoundException.java      |   46 +
 typesystem/pom.xml                              |    9 +-
 .../org/apache/atlas/ApplicationProperties.java |   86 --
 .../java/org/apache/atlas/AtlasException.java   |   44 -
 .../java/org/apache/atlas/ParamChecker.java     |  148 ---
 .../org/apache/atlas/TypeExistsException.java   |   25 -
 .../org/apache/atlas/TypeNotFoundException.java |   44 -
 .../org/apache/atlas/typesystem/IInstance.java  |    2 +
 .../apache/atlas/typesystem/ITypedInstance.java |    5 +-
 .../apache/atlas/typesystem/Referenceable.java  |   43 +-
 .../org/apache/atlas/typesystem/Struct.java     |   46 +
 .../exception/TypeExistsException.java          |   27 +
 .../exception/TypeNotFoundException.java        |   46 +
 .../persistence/DownCastStructInstance.java     |    5 +
 .../apache/atlas/typesystem/persistence/Id.java |   14 +
 .../persistence/ReferenceableInstance.java      |   14 +-
 .../typesystem/persistence/StructInstance.java  |   35 +
 .../typesystem/types/AttributeDefinition.java   |    2 +-
 .../atlas/typesystem/types/ClassType.java       |   28 +-
 .../atlas/typesystem/types/DataTypes.java       |   44 +-
 .../apache/atlas/typesystem/types/EnumType.java |   11 +-
 .../typesystem/types/EnumTypeDefinition.java    |    2 +-
 .../atlas/typesystem/types/EnumValue.java       |    2 +-
 .../atlas/typesystem/types/IDataType.java       |    4 +
 .../atlas/typesystem/types/Multiplicity.java    |    4 +-
 .../typesystem/types/ObjectGraphWalker.java     |    6 +
 .../atlas/typesystem/types/StructType.java      |   20 +
 .../typesystem/types/StructTypeDefinition.java  |    2 +-
 .../atlas/typesystem/types/TraitType.java       |   20 +
 .../atlas/typesystem/types/TypeSystem.java      |    4 +-
 .../atlas/typesystem/json/Serialization.scala   |   41 +-
 .../apache/atlas/web/filters/AuditFilter.java   |    6 +-
 .../atlas/web/resources/EntityResource.java     |  213 +++-
 .../web/resources/HiveLineageResource.java      |    4 +-
 .../resources/MetadataDiscoveryResource.java    |    2 +-
 .../atlas/web/resources/TypesResource.java      |    2 +-
 .../org/apache/atlas/web/util/Servlets.java     |    2 +-
 .../notification/EntityNotificationIT.java      |    2 +-
 .../NotificationHookConsumerIT.java             |    2 +-
 .../atlas/web/resources/BaseResourceIT.java     |    7 +-
 .../web/resources/EntityJerseyResourceIT.java   |  116 +-
 93 files changed, 4016 insertions(+), 2234 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/51656991/addons/hive-bridge/src/main/java/org/apache/atlas/hive/bridge/HiveMetaStoreBridge.java
----------------------------------------------------------------------
diff --git a/addons/hive-bridge/src/main/java/org/apache/atlas/hive/bridge/HiveMetaStoreBridge.java b/addons/hive-bridge/src/main/java/org/apache/atlas/hive/bridge/HiveMetaStoreBridge.java
index 90f3d96..f367317 100755
--- a/addons/hive-bridge/src/main/java/org/apache/atlas/hive/bridge/HiveMetaStoreBridge.java
+++ b/addons/hive-bridge/src/main/java/org/apache/atlas/hive/bridge/HiveMetaStoreBridge.java
@@ -479,12 +479,13 @@ public class HiveMetaStoreBridge {
         HiveDataModelGenerator dataModelGenerator = new HiveDataModelGenerator();
         AtlasClient dgiClient = getAtlasClient();
 
-        //Register hive data model if its not already registered
-        if (dgiClient.getType(HiveDataTypes.HIVE_PROCESS.getName()) == null) {
+        try {
+            dgiClient.getType(HiveDataTypes.HIVE_PROCESS.getName());
+            LOG.info("Hive data model is already registered!");
+        } catch(AtlasServiceException ase) {
+            //Expected in case types do not exist
             LOG.info("Registering Hive data model");
             dgiClient.createType(dataModelGenerator.getModelAsJson());
-        } else {
-            LOG.info("Hive data model is already registered!");
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/51656991/addons/hive-bridge/src/test/java/org/apache/atlas/hive/hook/HiveHookIT.java
----------------------------------------------------------------------
diff --git a/addons/hive-bridge/src/test/java/org/apache/atlas/hive/hook/HiveHookIT.java b/addons/hive-bridge/src/test/java/org/apache/atlas/hive/hook/HiveHookIT.java
index 643a29a..5447de5 100755
--- a/addons/hive-bridge/src/test/java/org/apache/atlas/hive/hook/HiveHookIT.java
+++ b/addons/hive-bridge/src/test/java/org/apache/atlas/hive/hook/HiveHookIT.java
@@ -20,7 +20,7 @@ package org.apache.atlas.hive.hook;
 
 import org.apache.atlas.ApplicationProperties;
 import org.apache.atlas.AtlasClient;
-import org.apache.atlas.ParamChecker;
+import org.apache.atlas.utils.ParamChecker;
 import org.apache.atlas.hive.bridge.HiveMetaStoreBridge;
 import org.apache.atlas.hive.model.HiveDataModelGenerator;
 import org.apache.atlas.hive.model.HiveDataTypes;

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/51656991/client/src/main/java/org/apache/atlas/AtlasClient.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/atlas/AtlasClient.java b/client/src/main/java/org/apache/atlas/AtlasClient.java
index 2e8a268..114548c 100755
--- a/client/src/main/java/org/apache/atlas/AtlasClient.java
+++ b/client/src/main/java/org/apache/atlas/AtlasClient.java
@@ -133,40 +133,43 @@ public class AtlasClient {
     enum API {
 
         //Type operations
-        CREATE_TYPE(BASE_URI + TYPES, HttpMethod.POST),
-        UPDATE_TYPE(BASE_URI + TYPES, HttpMethod.PUT),
-        GET_TYPE(BASE_URI + TYPES, HttpMethod.GET),
-        LIST_TYPES(BASE_URI + TYPES, HttpMethod.GET),
-        LIST_TRAIT_TYPES(BASE_URI + TYPES + "?type=trait", HttpMethod.GET),
+        CREATE_TYPE(BASE_URI + TYPES, HttpMethod.POST, Response.Status.CREATED),
+        UPDATE_TYPE(BASE_URI + TYPES, HttpMethod.PUT, Response.Status.OK),
+        GET_TYPE(BASE_URI + TYPES, HttpMethod.GET, Response.Status.OK),
+        LIST_TYPES(BASE_URI + TYPES, HttpMethod.GET, Response.Status.OK),
+        LIST_TRAIT_TYPES(BASE_URI + TYPES + "?type=trait", HttpMethod.GET, Response.Status.OK),
 
         //Entity operations
-        CREATE_ENTITY(BASE_URI + URI_ENTITY, HttpMethod.POST),
-        GET_ENTITY(BASE_URI + URI_ENTITY, HttpMethod.GET),
-        UPDATE_ENTITY(BASE_URI + URI_ENTITY, HttpMethod.PUT),
-        LIST_ENTITIES(BASE_URI + URI_ENTITY, HttpMethod.GET),
+        CREATE_ENTITY(BASE_URI + URI_ENTITY, HttpMethod.POST, Response.Status.CREATED),
+        GET_ENTITY(BASE_URI + URI_ENTITY, HttpMethod.GET, Response.Status.OK),
+        UPDATE_ENTITY(BASE_URI + URI_ENTITY, HttpMethod.PUT, Response.Status.OK),
+        UPDATE_ENTITY_PARTIAL(BASE_URI + URI_ENTITY, HttpMethod.POST, Response.Status.OK),
+        LIST_ENTITIES(BASE_URI + URI_ENTITY, HttpMethod.GET, Response.Status.OK),
 
         //Trait operations
-        ADD_TRAITS(BASE_URI + URI_ENTITY, HttpMethod.POST),
-        DELETE_TRAITS(BASE_URI + URI_ENTITY, HttpMethod.DELETE),
-        LIST_TRAITS(BASE_URI + URI_ENTITY, HttpMethod.GET),
+        ADD_TRAITS(BASE_URI + URI_ENTITY, HttpMethod.POST, Response.Status.CREATED),
+        DELETE_TRAITS(BASE_URI + URI_ENTITY, HttpMethod.DELETE, Response.Status.OK),
+        LIST_TRAITS(BASE_URI + URI_ENTITY, HttpMethod.GET, Response.Status.OK),
 
         //Search operations
-        SEARCH(BASE_URI + URI_SEARCH, HttpMethod.GET),
-        SEARCH_DSL(BASE_URI + URI_SEARCH + "/dsl", HttpMethod.GET),
-        SEARCH_GREMLIN(BASE_URI + URI_SEARCH + "/gremlin", HttpMethod.GET),
-        SEARCH_FULL_TEXT(BASE_URI + URI_SEARCH + "/fulltext", HttpMethod.GET),
+        SEARCH(BASE_URI + URI_SEARCH, HttpMethod.GET, Response.Status.OK),
+        SEARCH_DSL(BASE_URI + URI_SEARCH + "/dsl", HttpMethod.GET, Response.Status.OK),
+        SEARCH_GREMLIN(BASE_URI + URI_SEARCH + "/gremlin", HttpMethod.GET, Response.Status.OK),
+        SEARCH_FULL_TEXT(BASE_URI + URI_SEARCH + "/fulltext", HttpMethod.GET, Response.Status.OK),
 
         //Lineage operations
-        LINEAGE_INPUTS_GRAPH(BASE_URI + URI_LINEAGE, HttpMethod.GET),
-        LINEAGE_OUTPUTS_GRAPH(BASE_URI + URI_LINEAGE, HttpMethod.GET),
-        LINEAGE_SCHEMA(BASE_URI + URI_LINEAGE, HttpMethod.GET);
+        LINEAGE_INPUTS_GRAPH(BASE_URI + URI_LINEAGE, HttpMethod.GET, Response.Status.OK),
+        LINEAGE_OUTPUTS_GRAPH(BASE_URI + URI_LINEAGE, HttpMethod.GET, Response.Status.OK),
+        LINEAGE_SCHEMA(BASE_URI + URI_LINEAGE, HttpMethod.GET, Response.Status.OK);
 
         private final String method;
         private final String path;
+        private final Response.Status status;
 
-        API(String path, String method) {
+        API(String path, String method, Response.Status status) {
             this.path = path;
             this.method = method;
+            this.status = status;
         }
 
         public String getMethod() {
@@ -176,6 +179,8 @@ public class AtlasClient {
         public String getPath() {
             return path;
         }
+        
+        public Response.Status getExpectedStatus() { return status; }
     }
 
     /**
@@ -231,7 +236,7 @@ public class AtlasClient {
             JSONObject response = callAPIWithResource(API.GET_TYPE, resource);
             return response.getString(DEFINITION);
         } catch (AtlasServiceException e) {
-            if (e.getStatus() == ClientResponse.Status.NOT_FOUND) {
+            if (Response.Status.NOT_FOUND.equals(e.getStatus())) {
                 return null;
             }
             throw e;
@@ -266,11 +271,82 @@ public class AtlasClient {
     }
 
     public JSONArray createEntity(Referenceable... entities) throws AtlasServiceException {
+        JSONArray entityArray = getEntitiesArray(entities);
+        return createEntity(entityArray);
+    }
+
+    private JSONArray getEntitiesArray(Referenceable[] entities) {
         JSONArray entityArray = new JSONArray(entities.length);
         for (Referenceable entity : entities) {
             entityArray.put(InstanceSerialization.toJson(entity, true));
         }
-        return createEntity(entityArray);
+        return entityArray;
+    }
+
+    /**
+     * Replaces entity definitions identified by their guid or unique attribute
+     * Updates properties set in the definition for the entity corresponding to guid
+     * @param entities entities to be updated
+     * @return json array of guids which were updated/created
+     * @throws AtlasServiceException
+     */
+    public JSONArray updateEntities(Referenceable... entities) throws AtlasServiceException {
+        JSONArray entitiesArray = getEntitiesArray(entities);
+        JSONObject response = callAPI(API.UPDATE_ENTITY, entitiesArray.toString());
+        try {
+            return response.getJSONArray(GUID);
+        } catch (JSONException e) {
+            throw new AtlasServiceException(API.UPDATE_ENTITY, e);
+        }
+    }
+
+    /**
+     * Supports Partial updates
+     * Updates property for the entity corresponding to guid
+     * @param guid      guid
+     * @param attribute  property key
+     * @param value     property value
+     */
+    public void updateEntityAttribute(String guid, String attribute, String value) throws AtlasServiceException {
+        API api = API.UPDATE_ENTITY_PARTIAL;
+        WebResource resource = getResource(api, guid);
+        resource = resource.queryParam(ATTRIBUTE_NAME, attribute);
+        callAPIWithResource(api, resource, value);
+    }
+
+    /**
+     * Supports Partial updates
+     * Updates properties set in the definition for the entity corresponding to guid
+     * @param guid      guid
+     * @param entity entity definition
+     */
+    public void updateEntity(String guid, Referenceable entity) throws AtlasServiceException {
+        String entityJson = InstanceSerialization.toJson(entity, true);
+        callAPI(API.UPDATE_ENTITY_PARTIAL, entityJson, guid);
+    }
+
+    /**
+     * Supports Partial updates
+     * Updates properties set in the definition for the entity corresponding to guid
+     * @param entityType Type of the entity being updated
+     * @param uniqueAttributeName Attribute Name that uniquely identifies the entity
+     * @param uniqueAttributeValue Attribute Value that uniquely identifies the entity
+     * @param entity entity definition
+     */
+    public String updateEntity(String entityType, String uniqueAttributeName, String uniqueAttributeValue,
+                               Referenceable entity) throws AtlasServiceException {
+        API api = API.UPDATE_ENTITY_PARTIAL;
+        WebResource resource = getResource(api, "qualifiedName");
+        resource = resource.queryParam(TYPE, entityType);
+        resource = resource.queryParam(ATTRIBUTE_NAME, uniqueAttributeName);
+        resource = resource.queryParam(ATTRIBUTE_VALUE, uniqueAttributeValue);
+        String entityJson = InstanceSerialization.toJson(entity, true);
+        JSONObject response = callAPIWithResource(api, resource, entityJson);
+        try {
+            return response.getString(GUID);
+        } catch (JSONException e) {
+            throw new AtlasServiceException(api, e);
+        }
     }
 
     /**
@@ -351,19 +427,6 @@ public class AtlasClient {
     }
 
     /**
-     * Updates property for the entity corresponding to guid
-     * @param guid      guid
-     * @param property  property key
-     * @param value     property value
-     */
-    public JSONObject updateEntity(String guid, String property, String value) throws AtlasServiceException {
-        WebResource resource = getResource(API.UPDATE_ENTITY, guid);
-        resource = resource.queryParam(ATTRIBUTE_NAME, property);
-        resource = resource.queryParam(ATTRIBUTE_VALUE, value);
-        return callAPIWithResource(API.UPDATE_ENTITY, resource);
-    }
-
-    /**
      * Search using gremlin/dsl/full text
      * @param searchQuery
      * @return
@@ -488,13 +551,11 @@ public class AtlasClient {
     }
 
     private JSONObject callAPIWithResource(API api, WebResource resource, Object requestObject)
-    throws AtlasServiceException {
+        throws AtlasServiceException {
         ClientResponse clientResponse = resource.accept(JSON_MEDIA_TYPE).type(JSON_MEDIA_TYPE)
-                .method(api.getMethod(), ClientResponse.class, requestObject);
+            .method(api.getMethod(), ClientResponse.class, requestObject);
 
-        Response.Status expectedStatus =
-                HttpMethod.POST.equals(api.getMethod()) ? Response.Status.CREATED : Response.Status.OK;
-        if (clientResponse.getStatus() == expectedStatus.getStatusCode()) {
+        if (clientResponse.getStatus() == api.getExpectedStatus().getStatusCode()) {
             String responseAsString = clientResponse.getEntity(String.class);
             try {
                 return new JSONObject(responseAsString);

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/51656991/common/pom.xml
----------------------------------------------------------------------
diff --git a/common/pom.xml b/common/pom.xml
index 5498105..a7a5544 100644
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -33,13 +33,19 @@
 
     <dependencies>
         <dependency>
-            <groupId>org.apache.atlas</groupId>
-            <artifactId>atlas-typesystem</artifactId>
+            <groupId>org.testng</groupId>
+            <artifactId>testng</artifactId>
         </dependency>
 
         <dependency>
-            <groupId>org.testng</groupId>
-            <artifactId>testng</artifactId>
+            <groupId>com.google.inject</groupId>
+            <artifactId>guice</artifactId>
         </dependency>
+
+        <dependency>
+            <groupId>commons-configuration</groupId>
+            <artifactId>commons-configuration</artifactId>
+        </dependency>
+
     </dependencies>
 </project>

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/51656991/common/src/main/java/org/apache/atlas/ApplicationProperties.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/atlas/ApplicationProperties.java b/common/src/main/java/org/apache/atlas/ApplicationProperties.java
new file mode 100644
index 0000000..738ec53
--- /dev/null
+++ b/common/src/main/java/org/apache/atlas/ApplicationProperties.java
@@ -0,0 +1,86 @@
+/*
+ * 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.atlas;
+
+import org.apache.commons.configuration.CompositeConfiguration;
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Iterator;
+
+public class ApplicationProperties extends PropertiesConfiguration {
+    private static final Logger LOG = LoggerFactory.getLogger(ApplicationProperties.class);
+
+    public static final String APPLICATION_PROPERTIES = "application.properties";
+    public static final String CLIENT_PROPERTIES = "client.properties";
+
+    private static Configuration INSTANCE = null;
+
+    private ApplicationProperties(URL url) throws ConfigurationException {
+        super(url);
+    }
+
+    public static Configuration get() throws AtlasException {
+        if (INSTANCE == null) {
+            synchronized (ApplicationProperties.class) {
+                if (INSTANCE == null) {
+                    Configuration applicationProperties = get(APPLICATION_PROPERTIES);
+                    Configuration clientProperties = get(CLIENT_PROPERTIES);
+                    INSTANCE = new CompositeConfiguration(Arrays.asList(applicationProperties, clientProperties));
+                }
+            }
+        }
+        return INSTANCE;
+    }
+
+    public static Configuration get(String fileName) throws AtlasException {
+        String confLocation = System.getProperty("atlas.conf");
+        try {
+            URL url = confLocation == null ? ApplicationProperties.class.getResource("/" + fileName)
+                    : new File(confLocation, fileName).toURI().toURL();
+            LOG.info("Loading {} from {}", fileName, url);
+
+            Configuration configuration = new ApplicationProperties(url).interpolatedConfiguration();
+            logConfiguration(configuration);
+            return configuration;
+        } catch (Exception e) {
+            throw new AtlasException("Failed to load application properties", e);
+        }
+    }
+
+    private static void logConfiguration(Configuration configuration) {
+        if (LOG.isDebugEnabled()) {
+            Iterator<String> keys = configuration.getKeys();
+            LOG.debug("Configuration loaded:");
+            while (keys.hasNext()) {
+                String key = keys.next();
+                LOG.debug("{} = {}", key, configuration.getProperty(key));
+            }
+        }
+    }
+
+    public static final Configuration getSubsetConfiguration(Configuration inConf, String prefix) {
+        return inConf.subset(prefix);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/51656991/common/src/main/java/org/apache/atlas/AtlasException.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/atlas/AtlasException.java b/common/src/main/java/org/apache/atlas/AtlasException.java
new file mode 100644
index 0000000..2eb0658
--- /dev/null
+++ b/common/src/main/java/org/apache/atlas/AtlasException.java
@@ -0,0 +1,44 @@
+/**
+ * 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.atlas;
+
+/**
+ * Base Exception class for metadata API.
+ */
+public class AtlasException extends Exception {
+
+    public AtlasException() {
+    }
+
+    public AtlasException(String message) {
+        super(message);
+    }
+
+    public AtlasException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public AtlasException(Throwable cause) {
+        super(cause);
+    }
+
+    public AtlasException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/51656991/common/src/main/java/org/apache/atlas/listener/EntityChangeListener.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/atlas/listener/EntityChangeListener.java b/common/src/main/java/org/apache/atlas/listener/EntityChangeListener.java
deleted file mode 100644
index 08ed0d3..0000000
--- a/common/src/main/java/org/apache/atlas/listener/EntityChangeListener.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 org.apache.atlas.listener;
-
-import org.apache.atlas.AtlasException;
-import org.apache.atlas.typesystem.IStruct;
-import org.apache.atlas.typesystem.ITypedReferenceableInstance;
-
-import java.util.Collection;
-
-/**
- * Entity (a Typed instance) change notification listener.
- */
-public interface EntityChangeListener {
-
-    /**
-     * This is upon adding new entities to the repository.
-     *
-     * @param entities  the created entities
-     *
-     * @throws AtlasException if the listener notification fails
-     */
-    void onEntitiesAdded(Collection<ITypedReferenceableInstance> entities) throws AtlasException;
-
-    /**
-     * This is upon updating an entity.
-     *
-     * @param entity        the updated entity
-     *
-     * @throws AtlasException if the listener notification fails
-     */
-    void onEntityUpdated(ITypedReferenceableInstance entity) throws AtlasException;
-
-    /**
-     * This is upon adding a new trait to a typed instance.
-     *
-     * @param entity        the entity
-     * @param trait     trait that needs to be added to entity
-     *
-     * @throws AtlasException if the listener notification fails
-     */
-    void onTraitAdded(ITypedReferenceableInstance entity, IStruct trait) throws AtlasException;
-
-    /**
-     * This is upon deleting a trait from a typed instance.
-     *
-     * @param entity        the entity
-     * @param traitName     trait name for the instance that needs to be deleted from entity
-     *
-     * @throws AtlasException if the listener notification fails
-     */
-    void onTraitDeleted(ITypedReferenceableInstance entity, String traitName) throws AtlasException;
-}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/51656991/common/src/main/java/org/apache/atlas/listener/TypesChangeListener.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/atlas/listener/TypesChangeListener.java b/common/src/main/java/org/apache/atlas/listener/TypesChangeListener.java
deleted file mode 100644
index 5ff6d4a..0000000
--- a/common/src/main/java/org/apache/atlas/listener/TypesChangeListener.java
+++ /dev/null
@@ -1,49 +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 org.apache.atlas.listener;
-
-import org.apache.atlas.AtlasException;
-import org.apache.atlas.typesystem.types.IDataType;
-
-import java.util.Collection;
-
-/**
- * Types change notification listener.
- */
-public interface TypesChangeListener {
-
-    /**
-     * This is upon adding new type(s) to Store.
-     *
-     * @param dataTypes data type
-     * @throws AtlasException
-     */
-    void onAdd(Collection<? extends IDataType> dataTypes) throws AtlasException;
-
-    /**
-     * This is upon removing an existing type from the Store.
-     *
-     * @param typeName type name
-     * @throws AtlasException
-     */
-    // void onRemove(String typeName) throws MetadataException;
-
-     //This is upon updating an existing type to the store
-     void onChange(Collection<? extends IDataType> dataTypes) throws AtlasException;
-}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/51656991/common/src/main/java/org/apache/atlas/utils/MD5Utils.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/atlas/utils/MD5Utils.java b/common/src/main/java/org/apache/atlas/utils/MD5Utils.java
new file mode 100644
index 0000000..35e4744
--- /dev/null
+++ b/common/src/main/java/org/apache/atlas/utils/MD5Utils.java
@@ -0,0 +1,59 @@
+/*
+ * 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.atlas.utils;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+public class MD5Utils {
+
+    private static final ThreadLocal<MessageDigest> DIGESTER_FACTORY =
+        new ThreadLocal<MessageDigest>() {
+            @Override
+            protected MessageDigest initialValue() {
+                try {
+                    return MessageDigest.getInstance("MD5");
+                } catch (NoSuchAlgorithmException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        };
+
+    /**
+     * Create a thread local MD5 digester
+     */
+    public static MessageDigest getDigester() {
+        MessageDigest digester = DIGESTER_FACTORY.get();
+        digester.reset();
+        return digester;
+    }
+
+    private static final char[] HEX_DIGITS =
+        {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
+
+    public static String toString(byte[] digest) {
+        StringBuilder buf = new StringBuilder(MD5_LEN*2);
+        for (int i = 0; i < MD5_LEN; i++) {
+            int b = digest[i];
+            buf.append(HEX_DIGITS[(b >> 4) & 0xf]);
+            buf.append(HEX_DIGITS[b & 0xf]);
+        }
+        return buf.toString();
+    }
+
+    public static final int MD5_LEN = 16;
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/51656991/common/src/main/java/org/apache/atlas/utils/ParamChecker.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/atlas/utils/ParamChecker.java b/common/src/main/java/org/apache/atlas/utils/ParamChecker.java
new file mode 100644
index 0000000..ab543e6
--- /dev/null
+++ b/common/src/main/java/org/apache/atlas/utils/ParamChecker.java
@@ -0,0 +1,148 @@
+/*
+ * 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.atlas.utils;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+public class ParamChecker {
+
+    /**
+     * Check that a value is not null. If null throws an IllegalArgumentException.
+     *
+     * @param obj value.
+     * @param name parameter name for the exception message.
+     * @return the given value.
+     */
+    public static <T> T notNull(T obj, String name) {
+        if (obj == null) {
+            throw new IllegalArgumentException(name + " cannot be null");
+        }
+        return obj;
+    }
+
+    /**
+     * Check that a list is not null and that none of its elements is null. If null or if the list has emtpy elements
+     * throws an IllegalArgumentException.
+     *  @param list the list of T.
+     * @param name parameter name for the exception message.
+     */
+    public static <T> Collection<T> notNullElements(Collection<T> list, String name) {
+        notEmpty(list, name);
+        for (T ele : list) {
+            notNull(ele, String.format("Collection %s element %s", name, ele));
+        }
+        return list;
+    }
+
+    /**
+     * Check that a list is not null and that none of its elements is null. If null or if the list has emtpy elements
+     * throws an IllegalArgumentException.
+     *  @param array the array of T.
+     * @param name parameter name for the exception message.
+     */
+    public static <T> T[] notNullElements(T[] array, String name) {
+        notEmpty(Arrays.asList(array), name);
+        for (T ele : array) {
+            notNull(ele, String.format("Collection %s element %s", name, ele));
+        }
+        return array;
+    }
+
+    /**
+     * Check that a list is not null and not empty.
+     *  @param list the list of T.
+     * @param name parameter name for the exception message.
+     */
+    public static <T> Collection<T> notEmpty(Collection<T> list, String name) {
+        notNull(list, name);
+        if (list.isEmpty()) {
+            throw new IllegalArgumentException(String.format("Collection %s is empty", name));
+        }
+        return list;
+    }
+
+    /**
+     * Check that a string is not null and not empty. If null or emtpy throws an IllegalArgumentException.
+     *
+     * @param value value.
+     * @param name parameter name for the exception message.
+     * @return the given value.
+     */
+    public static String notEmpty(String value, String name) {
+        return notEmpty(value, name, null);
+    }
+
+    /**
+     * Check that a string is not empty if its not null.
+     *
+     * @param value value.
+     * @param name parameter name for the exception message.
+     * @return the given value.
+     */
+    public static String notEmptyIfNotNull(String value, String name) {
+        return notEmptyIfNotNull(value, name, null);
+    }
+
+    /**
+     * Check that a string is not empty if its not null.
+     *
+     * @param value value.
+     * @param name parameter name for the exception message.
+     * @return the given value.
+     */
+    public static String notEmptyIfNotNull(String value, String name, String info) {
+        if (value == null) {
+            return value;
+        }
+
+        if (value.trim().length() == 0) {
+            throw new IllegalArgumentException(name + " cannot be empty" + (info == null ? "" : ", " + info));
+        }
+        return value.trim();
+    }
+
+    /**
+     * Check that a string is not null and not empty. If null or emtpy throws an IllegalArgumentException.
+     *
+     * @param value value.
+     * @param name parameter name for the exception message.
+     * @param info additional information to be printed with the exception message
+     * @return the given value.
+     */
+    public static String notEmpty(String value, String name, String info) {
+        if (value == null) {
+            throw new IllegalArgumentException(name + " cannot be null" + (info == null ? "" : ", " + info));
+        }
+        return notEmptyIfNotNull(value, name, info);
+    }
+
+    /**
+     * Check that a list is not null and that none of its elements is null. If null or if the list has emtpy elements
+     * throws an IllegalArgumentException.
+     *  @param list the list of strings.
+     * @param name parameter name for the exception message.
+     */
+    public static Collection<String> notEmptyElements(Collection<String> list, String name) {
+        notEmpty(list, name);
+        for (String ele : list) {
+            notEmpty(ele, String.format("list %s element %s", name, ele));
+        }
+        return list;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/51656991/docs/src/site/twiki/Configuration.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/Configuration.twiki b/docs/src/site/twiki/Configuration.twiki
index 21d1c0e..526b300 100644
--- a/docs/src/site/twiki/Configuration.twiki
+++ b/docs/src/site/twiki/Configuration.twiki
@@ -60,8 +60,9 @@ Without Ranger, HBase shell can be used to set the permissions.
 </verbatim>
 
 ---++++ Graph Search Index
+
 This section sets up the graph db - titan - to use an search indexing system. The example
-configuration below setsup to use an embedded Elastic search indexing system.
+configuration below sets up to use an embedded Elastic search indexing system.
 
 <verbatim>
 atlas.graph.index.search.backend=elasticsearch
@@ -72,6 +73,7 @@ atlas.graph.index.search.elasticsearch.create.sleep=2000
 </verbatim>
 
 ---++++ Graph Search Index - Solr
+Please note that Solr installation in Cloud mode is a prerequisite before configuring Solr as the search indexing backend. Refer InstallationSteps section for Solr installation/configuration.
 
 <verbatim>
  atlas.graph.index.search.backend=solr5

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/51656991/docs/src/site/twiki/InstallationSteps.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/InstallationSteps.twiki b/docs/src/site/twiki/InstallationSteps.twiki
index 8d1f3d0..0eefb20 100644
--- a/docs/src/site/twiki/InstallationSteps.twiki
+++ b/docs/src/site/twiki/InstallationSteps.twiki
@@ -124,7 +124,7 @@ export METADATA_SERVER_OPTS="-Djava.awt.headless=true -Djava.security.krb5.realm
 * Hbase as the Storage Backend for the Graph Repository
 
 By default, Atlas uses Titan as the graph repository and is the only graph repository implementation available currently.
-The HBase versions currently supported are 0.98.x, 1.0.x, 1.1.x. For configuring ATLAS graph persistence on HBase, please go through the "Configuration - Graph persistence engine - HBase" section
+The HBase versions currently supported are 1.1.x. For configuring ATLAS graph persistence on HBase, please go through the "Configuration - Graph persistence engine - HBase" section
 for more details.
 
 Pre-requisites for running HBase as a distributed cluster

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/51656991/notification/pom.xml
----------------------------------------------------------------------
diff --git a/notification/pom.xml b/notification/pom.xml
index 796ea17..125ef75 100644
--- a/notification/pom.xml
+++ b/notification/pom.xml
@@ -48,6 +48,11 @@
         </dependency>
 
         <dependency>
+            <groupId>org.apache.atlas</groupId>
+            <artifactId>atlas-server-api</artifactId>
+        </dependency>
+
+        <dependency>
             <groupId>org.apache.kafka</groupId>
             <artifactId>kafka-clients</artifactId>
         </dependency>

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/51656991/notification/src/main/java/org/apache/atlas/notification/entity/NotificationEntityChangeListener.java
----------------------------------------------------------------------
diff --git a/notification/src/main/java/org/apache/atlas/notification/entity/NotificationEntityChangeListener.java b/notification/src/main/java/org/apache/atlas/notification/entity/NotificationEntityChangeListener.java
index 23a6d69..e2d16df 100644
--- a/notification/src/main/java/org/apache/atlas/notification/entity/NotificationEntityChangeListener.java
+++ b/notification/src/main/java/org/apache/atlas/notification/entity/NotificationEntityChangeListener.java
@@ -73,8 +73,8 @@ public class NotificationEntityChangeListener implements EntityChangeListener {
     }
 
     @Override
-    public void onEntityUpdated(ITypedReferenceableInstance entity) throws AtlasException {
-        notifyOfEntityEvent(Collections.singleton(entity), EntityNotification.OperationType.ENTITY_UPDATE);
+    public void onEntitiesUpdated(Collection<ITypedReferenceableInstance> entities) throws AtlasException {
+        notifyOfEntityEvent(entities, EntityNotification.OperationType.ENTITY_UPDATE);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/51656991/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 2f7ee82..929d255 100755
--- a/pom.xml
+++ b/pom.xml
@@ -407,6 +407,7 @@
     <modules>
         <module>common</module>
         <module>typesystem</module>
+        <module>server-api</module>
         <module>notification</module>
         <module>client</module>
         <module>titan</module>
@@ -932,6 +933,12 @@
 
             <dependency>
                 <groupId>org.apache.atlas</groupId>
+                <artifactId>atlas-server-api</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.apache.atlas</groupId>
                 <artifactId>atlas-repository</artifactId>
                 <version>${project.version}</version>
             </dependency>

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/51656991/release-log.txt
----------------------------------------------------------------------
diff --git a/release-log.txt b/release-log.txt
index 4ebba32..1dae6fb 100644
--- a/release-log.txt
+++ b/release-log.txt
@@ -14,6 +14,7 @@ ATLAS-54 Rename configs in hive hook (shwethags)
 ATLAS-3 Mixed Index creation fails with Date types (sumasai via shwethags)
 
 ALL CHANGES:
+ATLAS-47 Entity mutations for complex types (sumasai via shwethags)
 ATLAS-345 UI: Should allow tag addition on any search result that returns a reference-able entity (darshankumar89 via shwethags)
 ATLAS-279 UI not displaying results for certain successful "select" search queries (anilsg via shwethags)
 ATLAS-242 The qualified name for hive entities should be backward compatible (shwethags)

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/51656991/repository/pom.xml
----------------------------------------------------------------------
diff --git a/repository/pom.xml b/repository/pom.xml
index 6e1baee..5810956 100755
--- a/repository/pom.xml
+++ b/repository/pom.xml
@@ -41,7 +41,7 @@
 
         <dependency>
             <groupId>org.apache.atlas</groupId>
-            <artifactId>atlas-common</artifactId>
+            <artifactId>atlas-server-api</artifactId>
         </dependency>
 
         <dependency>

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/51656991/repository/src/main/java/org/apache/atlas/RepositoryMetadataModule.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/RepositoryMetadataModule.java b/repository/src/main/java/org/apache/atlas/RepositoryMetadataModule.java
index b12c9a8..f77c237 100755
--- a/repository/src/main/java/org/apache/atlas/RepositoryMetadataModule.java
+++ b/repository/src/main/java/org/apache/atlas/RepositoryMetadataModule.java
@@ -49,11 +49,13 @@ public class RepositoryMetadataModule extends com.google.inject.AbstractModule {
     @Override
     protected void configure() {
         // special wiring for Titan Graph
+
+
+
         ThrowingProviderBinder.create(binder()).bind(GraphProvider.class, TitanGraph.class).to(TitanGraphProvider.class)
                 .asEagerSingleton();
 
         // allow for dynamic binding of the metadata repo & graph service
-
         // bind the MetadataRepositoryService interface to an implementation
         bind(MetadataRepository.class).to(GraphBackedMetadataRepository.class).asEagerSingleton();
 

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/51656991/repository/src/main/java/org/apache/atlas/discovery/DiscoveryException.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/discovery/DiscoveryException.java b/repository/src/main/java/org/apache/atlas/discovery/DiscoveryException.java
deleted file mode 100755
index ba69af7..0000000
--- a/repository/src/main/java/org/apache/atlas/discovery/DiscoveryException.java
+++ /dev/null
@@ -1,74 +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 org.apache.atlas.discovery;
-
-import org.apache.atlas.AtlasException;
-
-import java.security.PrivilegedActionException;
-
-public class DiscoveryException extends AtlasException {
-
-    /**
-     * 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 DiscoveryException(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.)
-     * @since 1.4
-     */
-    public DiscoveryException(String message, Throwable cause) {
-        super(message, cause);
-    }
-
-    /**
-     * Constructs a new exception with the specified cause and a detail
-     * message of <tt>(cause==null ? null : cause.toString())</tt> (which
-     * typically contains the class and detail message of <tt>cause</tt>).
-     * This constructor is useful for exceptions that are little more than
-     * wrappers for other throwables (for example, {@link
-     * PrivilegedActionException}).
-     *
-     * @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.)
-     * @since 1.4
-     */
-    public DiscoveryException(Throwable cause) {
-        super(cause);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/51656991/repository/src/main/java/org/apache/atlas/discovery/DiscoveryService.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/discovery/DiscoveryService.java b/repository/src/main/java/org/apache/atlas/discovery/DiscoveryService.java
deleted file mode 100755
index e347c2c..0000000
--- a/repository/src/main/java/org/apache/atlas/discovery/DiscoveryService.java
+++ /dev/null
@@ -1,52 +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 org.apache.atlas.discovery;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * Metadata discovery service.
- */
-public interface DiscoveryService {
-
-    /**
-     * Full text search
-     */
-    String searchByFullText(String query) throws DiscoveryException;
-
-    /**
-     * Search using query DSL.
-     *
-     * @param dslQuery query in DSL format.
-     * @return JSON representing the type and results.
-     */
-    String searchByDSL(String dslQuery) throws DiscoveryException;
-
-    /**
-     * Assumes the User is familiar with the persistence structure of the Repository.
-     * The given query is run uninterpreted against the underlying Graph Store.
-     * The results are returned as a List of Rows. each row is a Map of Key,Value pairs.
-     *
-     * @param gremlinQuery query in gremlin dsl format
-     * @return List of Maps
-     * @throws org.apache.atlas.discovery.DiscoveryException
-     */
-    List<Map<String, String>> searchByGremlin(String gremlinQuery) throws DiscoveryException;
-}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/51656991/repository/src/main/java/org/apache/atlas/discovery/HiveLineageService.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/discovery/HiveLineageService.java b/repository/src/main/java/org/apache/atlas/discovery/HiveLineageService.java
index 7a6ff55..00905d7 100644
--- a/repository/src/main/java/org/apache/atlas/discovery/HiveLineageService.java
+++ b/repository/src/main/java/org/apache/atlas/discovery/HiveLineageService.java
@@ -22,14 +22,14 @@ import com.thinkaurelius.titan.core.TitanGraph;
 import org.apache.atlas.ApplicationProperties;
 import org.apache.atlas.AtlasException;
 import org.apache.atlas.GraphTransaction;
-import org.apache.atlas.ParamChecker;
+import org.apache.atlas.typesystem.exception.EntityNotFoundException;
+import org.apache.atlas.utils.ParamChecker;
 import org.apache.atlas.discovery.graph.DefaultGraphPersistenceStrategy;
 import org.apache.atlas.discovery.graph.GraphBackedDiscoveryService;
 import org.apache.atlas.query.Expressions;
 import org.apache.atlas.query.GremlinQueryResult;
 import org.apache.atlas.query.HiveLineageQuery;
 import org.apache.atlas.query.HiveWhereUsedQuery;
-import org.apache.atlas.repository.EntityNotFoundException;
 import org.apache.atlas.repository.MetadataRepository;
 import org.apache.atlas.repository.graph.GraphProvider;
 import org.apache.atlas.typesystem.persistence.ReferenceableInstance;

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/51656991/repository/src/main/java/org/apache/atlas/discovery/LineageService.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/discovery/LineageService.java b/repository/src/main/java/org/apache/atlas/discovery/LineageService.java
deleted file mode 100644
index 8dc36cd..0000000
--- a/repository/src/main/java/org/apache/atlas/discovery/LineageService.java
+++ /dev/null
@@ -1,67 +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 org.apache.atlas.discovery;
-
-import org.apache.atlas.AtlasException;
-
-/**
- * Lineage service interface.
- */
-public interface LineageService {
-
-    /**
-     * Return the lineage outputs for the given tableName.
-     *
-     * @param tableName tableName
-     * @return Outputs as JSON
-     */
-    String getOutputs(String tableName) throws AtlasException;
-
-    /**
-     * Return the lineage outputs graph for the given tableName.
-     *
-     * @param tableName tableName
-     * @return Outputs Graph as JSON
-     */
-    String getOutputsGraph(String tableName) throws AtlasException;
-
-    /**
-     * Return the lineage inputs for the given tableName.
-     *
-     * @param tableName tableName
-     * @return Inputs as JSON
-     */
-    String getInputs(String tableName) throws AtlasException;
-
-    /**
-     * Return the lineage inputs graph for the given tableName.
-     *
-     * @param tableName tableName
-     * @return Inputs Graph as JSON
-     */
-    String getInputsGraph(String tableName) throws AtlasException;
-
-    /**
-     * Return the schema for the given tableName.
-     *
-     * @param tableName tableName
-     * @return Schema as JSON
-     */
-    String getSchema(String tableName) throws AtlasException;
-}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/51656991/repository/src/main/java/org/apache/atlas/discovery/graph/DefaultGraphPersistenceStrategy.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/discovery/graph/DefaultGraphPersistenceStrategy.java b/repository/src/main/java/org/apache/atlas/discovery/graph/DefaultGraphPersistenceStrategy.java
index 65a46a4..90718ed 100755
--- a/repository/src/main/java/org/apache/atlas/discovery/graph/DefaultGraphPersistenceStrategy.java
+++ b/repository/src/main/java/org/apache/atlas/discovery/graph/DefaultGraphPersistenceStrategy.java
@@ -30,6 +30,7 @@ import org.apache.atlas.query.TypeUtils;
 import org.apache.atlas.repository.Constants;
 import org.apache.atlas.repository.MetadataRepository;
 import org.apache.atlas.repository.graph.GraphBackedMetadataRepository;
+import org.apache.atlas.repository.graph.GraphHelper;
 import org.apache.atlas.typesystem.ITypedReferenceableInstance;
 import org.apache.atlas.typesystem.ITypedStruct;
 import org.apache.atlas.typesystem.persistence.Id;
@@ -43,7 +44,7 @@ import org.apache.atlas.typesystem.types.TypeSystem;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.ArrayList;
+import javax.inject.Inject;
 import java.util.List;
 
 /**
@@ -55,6 +56,7 @@ public class DefaultGraphPersistenceStrategy implements GraphPersistenceStrategi
 
     private final GraphBackedMetadataRepository metadataRepository;
 
+    @Inject
     public DefaultGraphPersistenceStrategy(MetadataRepository metadataRepository) {
         this.metadataRepository = (GraphBackedMetadataRepository) metadataRepository;
     }
@@ -71,7 +73,11 @@ public class DefaultGraphPersistenceStrategy implements GraphPersistenceStrategi
 
     @Override
     public String edgeLabel(IDataType<?> dataType, AttributeInfo aInfo) {
-        return metadataRepository.getEdgeLabel(dataType, aInfo);
+        try {
+            return metadataRepository.getEdgeLabel(dataType, aInfo);
+        } catch (AtlasException e) {
+            throw new RuntimeException(e);
+        }
     }
 
     @Override
@@ -90,7 +96,7 @@ public class DefaultGraphPersistenceStrategy implements GraphPersistenceStrategi
 
     @Override
     public List<String> traitNames(TitanVertex vertex) {
-        return metadataRepository.getTraitNames(vertex);
+        return GraphHelper.getTraitNames(vertex);
     }
 
     @Override
@@ -100,7 +106,7 @@ public class DefaultGraphPersistenceStrategy implements GraphPersistenceStrategi
 
     @Override
     public Id getIdFromVertex(String dataTypeName, TitanVertex vertex) {
-        return metadataRepository.getIdFromVertex(dataTypeName, vertex);
+        return GraphHelper.getIdFromVertex(dataTypeName, vertex);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/51656991/repository/src/main/java/org/apache/atlas/repository/EntityExistsException.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/EntityExistsException.java b/repository/src/main/java/org/apache/atlas/repository/EntityExistsException.java
deleted file mode 100644
index 7ea7e41..0000000
--- a/repository/src/main/java/org/apache/atlas/repository/EntityExistsException.java
+++ /dev/null
@@ -1,32 +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
- * <p/>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p/>
- * 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.atlas.repository;
-
-import org.apache.atlas.AtlasException;
-import org.apache.atlas.typesystem.IReferenceableInstance;
-
-public class EntityExistsException extends AtlasException {
-    public EntityExistsException(IReferenceableInstance typedInstance, Exception e) {
-        super("Model violation for type "+ typedInstance.getTypeName(), e);
-    }
-
-    public EntityExistsException(IReferenceableInstance typedInstance) {
-        super("Model violation for type "+ typedInstance.getTypeName());
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/51656991/repository/src/main/java/org/apache/atlas/repository/EntityNotFoundException.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/EntityNotFoundException.java b/repository/src/main/java/org/apache/atlas/repository/EntityNotFoundException.java
deleted file mode 100644
index db21bc7..0000000
--- a/repository/src/main/java/org/apache/atlas/repository/EntityNotFoundException.java
+++ /dev/null
@@ -1,44 +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 org.apache.atlas.repository;
-
-/**
- * A simple wrapper for 404.
- */
-public class EntityNotFoundException extends RepositoryException {
-    public EntityNotFoundException() {
-    }
-
-    public EntityNotFoundException(String message) {
-        super(message);
-    }
-
-    public EntityNotFoundException(String message, Throwable cause) {
-        super(message, cause);
-    }
-
-    public EntityNotFoundException(Throwable cause) {
-        super(cause);
-    }
-
-    public EntityNotFoundException(String message, Throwable cause, boolean enableSuppression,
-            boolean writableStackTrace) {
-        super(message, cause, enableSuppression, writableStackTrace);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/51656991/repository/src/main/java/org/apache/atlas/repository/MetadataRepository.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/MetadataRepository.java b/repository/src/main/java/org/apache/atlas/repository/MetadataRepository.java
index c11d9a0..2091e71 100755
--- a/repository/src/main/java/org/apache/atlas/repository/MetadataRepository.java
+++ b/repository/src/main/java/org/apache/atlas/repository/MetadataRepository.java
@@ -19,6 +19,8 @@
 package org.apache.atlas.repository;
 
 import org.apache.atlas.AtlasException;
+import org.apache.atlas.typesystem.exception.EntityExistsException;
+import org.apache.atlas.typesystem.exception.EntityNotFoundException;
 import org.apache.atlas.typesystem.ITypedReferenceableInstance;
 import org.apache.atlas.typesystem.ITypedStruct;
 import org.apache.atlas.typesystem.types.AttributeInfo;
@@ -70,7 +72,7 @@ public interface MetadataRepository {
      * @param aInfo    attribute info
      * @return edge label for a given attribute
      */
-    String getEdgeLabel(IDataType<?> dataType, AttributeInfo aInfo);
+    String getEdgeLabel(IDataType<?> dataType, AttributeInfo aInfo) throws AtlasException;
 
     /**
      * Creates an entity definition (instance) corresponding to a given type.
@@ -89,7 +91,7 @@ public interface MetadataRepository {
      * @return entity (typed instance) definition
      * @throws RepositoryException
      */
-    ITypedReferenceableInstance getEntityDefinition(String guid) throws RepositoryException;
+    ITypedReferenceableInstance getEntityDefinition(String guid) throws RepositoryException, EntityNotFoundException;
 
     /**
      * Gets the list of entities for a given entity type.
@@ -108,20 +110,6 @@ public interface MetadataRepository {
      * @throws RepositoryException
      */
     // boolean deleteEntity(String guid) throws RepositoryException;
-
-    /**
-     * Updates an entity given its GUID with the attribute name and value.
-     *
-     * @param guid           globally unique identifier for the entity
-     * @param attributeName  name of the attribute
-     * @param attributeValue value of the attribute
-     * @return an entity instance with updated state
-     * @throws RepositoryException
-     */
-    //ITypedReferenceableInstance updateEntity(String guid, String attributeName,
-    //                                         String attributeValue) throws RepositoryException;
-
-
     // Trait management functions
 
     /**
@@ -149,15 +137,19 @@ public interface MetadataRepository {
      * @param traitNameToBeDeleted name of the trait
      * @throws RepositoryException
      */
-    void deleteTrait(String guid, String traitNameToBeDeleted) throws RepositoryException;
+    void deleteTrait(String guid, String traitNameToBeDeleted) throws EntityNotFoundException, RepositoryException;
+
+    /**
+     * Adds/Updates the property to the entity that corresponds to the GUID
+     * Supports only primitive attribute/Class Id updations.
+     */
+    void updatePartial(ITypedReferenceableInstance entity) throws RepositoryException;
 
     /**
-     * Adds/Updates the property to/in the entity that corresponds to the GUID
-     * @param guid entity id
-     * @param property property name
-     * @param value    property value
+     * Adds the property to the entity that corresponds to the GUID
+     * @param entitiesToBeUpdated The entities to be updated
      */
-    void updateEntity(String guid, String property, String value) throws RepositoryException;
+    String[] updateEntities(ITypedReferenceableInstance... entitiesToBeUpdated) throws RepositoryException;
 
     /**
      * Returns the entity for the given type and qualified name
@@ -166,5 +158,5 @@ public interface MetadataRepository {
      * @param value
      * @return entity instance
      */
-    ITypedReferenceableInstance getEntityDefinition(String entityType, String attribute, String value) throws AtlasException;
+    ITypedReferenceableInstance getEntityDefinition(String entityType, String attribute, Object value) throws AtlasException;
 }

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/51656991/repository/src/main/java/org/apache/atlas/repository/graph/EntityProcessor.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/graph/EntityProcessor.java b/repository/src/main/java/org/apache/atlas/repository/graph/EntityProcessor.java
new file mode 100644
index 0000000..59472e4
--- /dev/null
+++ b/repository/src/main/java/org/apache/atlas/repository/graph/EntityProcessor.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.atlas.repository.graph;
+
+import org.apache.atlas.AtlasException;
+import org.apache.atlas.repository.RepositoryException;
+import org.apache.atlas.typesystem.IReferenceableInstance;
+import org.apache.atlas.typesystem.ITypedReferenceableInstance;
+import org.apache.atlas.typesystem.persistence.Id;
+import org.apache.atlas.typesystem.types.DataTypes;
+import org.apache.atlas.typesystem.types.ObjectGraphWalker;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public final class EntityProcessor implements ObjectGraphWalker.NodeProcessor {
+
+    private final Map<Id, IReferenceableInstance> idToInstanceMap;
+
+    public EntityProcessor() {
+        idToInstanceMap = new LinkedHashMap<>();
+    }
+
+    public Collection<IReferenceableInstance> getInstances() {
+        ArrayList<IReferenceableInstance> instances = new ArrayList<IReferenceableInstance>(idToInstanceMap.values());
+        Collections.reverse(instances);
+        return instances;
+    }
+
+    @Override
+    public void processNode(ObjectGraphWalker.Node nd) throws AtlasException {
+        IReferenceableInstance ref = null;
+        Id id = null;
+
+        if (nd.attributeName == null) {
+            ref = (IReferenceableInstance) nd.instance;
+            id = ref.getId();
+        } else if (nd.aInfo.dataType().getTypeCategory() == DataTypes.TypeCategory.CLASS) {
+            if (nd.value != null && (nd.value instanceof Id)) {
+                id = (Id) nd.value;
+            }
+        }
+
+        if (id != null) {
+            if (id.isUnassigned()) {
+                if (ref != null) {
+                    if (idToInstanceMap.containsKey(id)) { // Oops
+                        throw new RepositoryException(
+                            String.format("Unexpected internal error: Id %s processed again", id));
+                    }
+
+                    idToInstanceMap.put(id, ref);
+                }
+            }
+        }
+    }
+
+    public void addInstanceIfNotExists(ITypedReferenceableInstance ref) {
+        if(!idToInstanceMap.containsKey(ref.getId())) {
+            idToInstanceMap.put(ref.getId(), ref);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/51656991/repository/src/main/java/org/apache/atlas/repository/graph/FullTextMapper.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/graph/FullTextMapper.java b/repository/src/main/java/org/apache/atlas/repository/graph/FullTextMapper.java
new file mode 100644
index 0000000..36d8034
--- /dev/null
+++ b/repository/src/main/java/org/apache/atlas/repository/graph/FullTextMapper.java
@@ -0,0 +1,146 @@
+/**
+ * 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.atlas.repository.graph;
+
+import com.tinkerpop.blueprints.Vertex;
+import org.apache.atlas.AtlasException;
+import org.apache.atlas.repository.Constants;
+import org.apache.atlas.typesystem.ITypedInstance;
+import org.apache.atlas.typesystem.ITypedReferenceableInstance;
+import org.apache.atlas.typesystem.types.AttributeInfo;
+import org.apache.atlas.typesystem.types.DataTypes;
+import org.apache.atlas.typesystem.types.EnumValue;
+import org.apache.atlas.typesystem.types.IDataType;
+import org.apache.commons.lang.StringUtils;
+
+import java.util.List;
+import java.util.Map;
+
+public class FullTextMapper {
+
+    private final GraphToTypedInstanceMapper graphToTypedInstanceMapper;
+
+    private static final GraphHelper graphHelper = GraphHelper.getInstance();
+
+    private static final String FULL_TEXT_DELIMITER = " ";
+
+    FullTextMapper(GraphToTypedInstanceMapper graphToTypedInstanceMapper) {
+        this.graphToTypedInstanceMapper = graphToTypedInstanceMapper;
+    }
+
+    public String mapRecursive(Vertex instanceVertex, boolean followReferences) throws AtlasException {
+        String guid = instanceVertex.getProperty(Constants.GUID_PROPERTY_KEY);
+        ITypedReferenceableInstance typedReference =
+            graphToTypedInstanceMapper.mapGraphToTypedInstance(guid, instanceVertex);
+        String fullText = forInstance(typedReference, followReferences);
+        StringBuilder fullTextBuilder =
+            new StringBuilder(typedReference.getTypeName()).append(FULL_TEXT_DELIMITER).append(fullText);
+
+        List<String> traits = typedReference.getTraits();
+        for (String traitName : traits) {
+            String traitText = forInstance((ITypedInstance) typedReference.getTrait(traitName), false);
+            fullTextBuilder.append(FULL_TEXT_DELIMITER).append(traitName).append(FULL_TEXT_DELIMITER)
+                .append(traitText);
+        }
+        return fullTextBuilder.toString();
+    }
+
+    private String forAttribute(IDataType type, Object value, boolean followReferences)
+        throws AtlasException {
+        if (value == null) {
+            return null;
+        }
+        switch (type.getTypeCategory()) {
+        case PRIMITIVE:
+            return String.valueOf(value);
+        case ENUM:
+
+            return ((EnumValue) value).value;
+
+        case ARRAY:
+            StringBuilder fullText = new StringBuilder();
+            IDataType elemType = ((DataTypes.ArrayType) type).getElemType();
+            List list = (List) value;
+
+            for (Object element : list) {
+                String elemFullText = forAttribute(elemType, element, false);
+                if (StringUtils.isNotEmpty(elemFullText)) {
+                    fullText = fullText.append(FULL_TEXT_DELIMITER).append(elemFullText);
+                }
+            }
+            return fullText.toString();
+
+        case MAP:
+            fullText = new StringBuilder();
+            IDataType keyType = ((DataTypes.MapType) type).getKeyType();
+            IDataType valueType = ((DataTypes.MapType) type).getValueType();
+            Map map = (Map) value;
+
+            for (Object entryObj : map.entrySet()) {
+                Map.Entry entry = (Map.Entry) entryObj;
+                String keyFullText = forAttribute(keyType, entry.getKey(), false);
+                if (StringUtils.isNotEmpty(keyFullText)) {
+                    fullText = fullText.append(FULL_TEXT_DELIMITER).append(keyFullText);
+                }
+                String valueFullText = forAttribute(valueType, entry.getValue(), false);
+                if (StringUtils.isNotEmpty(valueFullText)) {
+                    fullText = fullText.append(FULL_TEXT_DELIMITER).append(valueFullText);
+                }
+            }
+            return fullText.toString();
+
+        case CLASS:
+            if (followReferences) {
+                String refGuid = ((ITypedReferenceableInstance) value).getId()._getId();
+                Vertex refVertex = graphHelper.getVertexForGUID(refGuid);
+                return mapRecursive(refVertex, false);
+            }
+            break;
+
+        case STRUCT:
+            if (followReferences) {
+                return forInstance((ITypedInstance) value, true);
+            }
+            break;
+
+        default:
+            throw new IllegalStateException("Unhandled type category " + type.getTypeCategory());
+
+        }
+        return null;
+    }
+
+    private String forInstance(ITypedInstance typedInstance, boolean followReferences)
+        throws AtlasException {
+        StringBuilder fullText = new StringBuilder();
+        for (AttributeInfo attributeInfo : typedInstance.fieldMapping().fields.values()) {
+            Object attrValue = typedInstance.get(attributeInfo.name);
+            if (attrValue == null) {
+                continue;
+            }
+
+            String attrFullText = forAttribute(attributeInfo.dataType(), attrValue, followReferences);
+            if (StringUtils.isNotEmpty(attrFullText)) {
+                fullText =
+                    fullText.append(FULL_TEXT_DELIMITER).append(attributeInfo.name).append(FULL_TEXT_DELIMITER)
+                        .append(attrFullText);
+            }
+        }
+        return fullText.toString();
+    }
+}