You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@atlas.apache.org by yh...@apache.org on 2016/05/18 13:04:01 UTC

[5/5] incubator-atlas git commit: ATLAS-491 Business Catalog / Taxonomy (jspeidel via yhemanth)

ATLAS-491 Business Catalog / Taxonomy (jspeidel via yhemanth)


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

Branch: refs/heads/master
Commit: aaf2971ad16ccd9c37040f593121695cd8c9cacb
Parents: b65dd91
Author: Hemanth Yamijala <hy...@hortonworks.com>
Authored: Wed May 18 18:33:39 2016 +0530
Committer: Hemanth Yamijala <hy...@hortonworks.com>
Committed: Wed May 18 18:33:39 2016 +0530

----------------------------------------------------------------------
 catalog/pom.xml                                 | 122 +++++
 .../apache/atlas/catalog/AtlasTypeSystem.java   |  79 ++++
 .../org/apache/atlas/catalog/BaseRequest.java   |  62 +++
 .../atlas/catalog/BaseResourceProvider.java     |  40 ++
 .../apache/atlas/catalog/CollectionRequest.java |  35 ++
 .../atlas/catalog/DefaultDateFormatter.java     |  39 ++
 .../atlas/catalog/DefaultPropertyMapper.java    | 142 ++++++
 .../apache/atlas/catalog/DefaultTypeSystem.java | 130 ++++++
 .../atlas/catalog/EntityResourceProvider.java   |  72 +++
 .../catalog/EntityTagResourceProvider.java      | 135 ++++++
 .../apache/atlas/catalog/InstanceRequest.java   |  35 ++
 .../apache/atlas/catalog/JsonSerializer.java    |  90 ++++
 .../apache/atlas/catalog/PropertyMapper.java    |  45 ++
 .../atlas/catalog/PropertyValueFormatter.java   |  33 ++
 .../java/org/apache/atlas/catalog/Request.java  |  77 ++++
 .../atlas/catalog/ResourceComparator.java       |  62 +++
 .../apache/atlas/catalog/ResourceProvider.java  |  75 ++++
 .../java/org/apache/atlas/catalog/Result.java   |  50 +++
 .../atlas/catalog/TaxonomyResourceProvider.java |  80 ++++
 .../java/org/apache/atlas/catalog/TermPath.java | 111 +++++
 .../atlas/catalog/TermResourceProvider.java     | 128 ++++++
 .../apache/atlas/catalog/TermVertexWrapper.java |  36 ++
 .../org/apache/atlas/catalog/VertexWrapper.java | 111 +++++
 .../definition/BaseResourceDefinition.java      | 150 +++++++
 .../definition/EntityResourceDefinition.java    | 120 +++++
 .../definition/EntityTagResourceDefinition.java | 105 +++++
 .../catalog/definition/ResourceDefinition.java  | 112 +++++
 .../definition/TaxonomyResourceDefinition.java  |  89 ++++
 .../definition/TermResourceDefinition.java      | 158 +++++++
 .../catalog/exception/CatalogException.java     |  36 ++
 .../exception/CatalogRuntimeException.java      |  43 ++
 .../exception/InvalidPayloadException.java      |  39 ++
 .../exception/InvalidQueryException.java        |  28 ++
 .../ResourceAlreadyExistsException.java         |  28 ++
 .../exception/ResourceNotFoundException.java    |  28 ++
 .../catalog/projection/GenericRelation.java     |  80 ++++
 .../atlas/catalog/projection/Projection.java    |  66 +++
 .../catalog/projection/ProjectionResult.java    |  51 +++
 .../atlas/catalog/projection/Relation.java      |  53 +++
 .../catalog/projection/RelationProjection.java  |  69 +++
 .../atlas/catalog/projection/RelationSet.java   |  45 ++
 .../atlas/catalog/projection/TagRelation.java   |  73 +++
 .../atlas/catalog/projection/TraitRelation.java |  76 ++++
 .../catalog/query/AlwaysQueryExpression.java    |  46 ++
 .../atlas/catalog/query/AtlasEntityQuery.java   |  40 ++
 .../catalog/query/AtlasEntityTagQuery.java      |  73 +++
 .../apache/atlas/catalog/query/AtlasQuery.java  |  37 ++
 .../atlas/catalog/query/AtlasTaxonomyQuery.java |  37 ++
 .../atlas/catalog/query/AtlasTermQuery.java     |  44 ++
 .../apache/atlas/catalog/query/BaseQuery.java   | 121 +++++
 .../catalog/query/BaseQueryExpression.java      | 105 +++++
 .../catalog/query/BooleanQueryExpression.java   | 141 ++++++
 .../catalog/query/PrefixQueryExpression.java    |  39 ++
 .../query/ProjectionQueryExpression.java        | 122 +++++
 .../atlas/catalog/query/QueryExpression.java    |  99 +++++
 .../atlas/catalog/query/QueryFactory.java       | 182 ++++++++
 .../catalog/query/RegexQueryExpression.java     |  41 ++
 .../catalog/query/TermQueryExpression.java      |  52 +++
 .../catalog/query/TermRangeQueryExpression.java |  61 +++
 .../catalog/query/WildcardQueryExpression.java  |  43 ++
 .../atlas/catalog/CollectionRequestTest.java    |  74 ++++
 .../atlas/catalog/DefaultDateFormatterTest.java |  41 ++
 .../catalog/DefaultPropertyMapperTest.java      | 177 ++++++++
 .../catalog/EntityResourceProviderTest.java     | 215 +++++++++
 .../catalog/EntityTagResourceProviderTest.java  | 444 +++++++++++++++++++
 .../atlas/catalog/InstanceRequestTest.java      |  67 +++
 .../atlas/catalog/JsonSerializerTest.java       | 120 +++++
 .../atlas/catalog/ResourceComparatorTest.java   |  61 +++
 .../catalog/TaxonomyResourceProviderTest.java   | 287 ++++++++++++
 .../atlas/catalog/TermResourceProviderTest.java | 355 +++++++++++++++
 .../apache/atlas/catalog/VertexWrapperTest.java | 311 +++++++++++++
 .../EntityResourceDefinitionTest.java           | 140 ++++++
 .../EntityTagResourceDefinitionTest.java        | 177 ++++++++
 .../TaxonomyResourceDefinitionTest.java         | 174 ++++++++
 .../definition/TermResourceDefinitionTest.java  | 210 +++++++++
 .../query/AlwaysQueryExpressionTest.java        |  74 ++++
 .../atlas/catalog/query/QueryFactoryTest.java   | 209 +++++++++
 distro/src/conf/policy-store.txt                |  10 +-
 pom.xml                                         |   9 +-
 release-log.txt                                 |   1 +
 .../atlas/services/DefaultMetadataService.java  |  50 ++-
 .../apache/atlas/services/MetadataService.java  |  28 ++
 webapp/pom.xml                                  |   5 +
 .../authorize/AtlasAuthorizationUtils.java      |  25 +-
 .../atlas/authorize/AtlasResourceTypes.java     |   2 +-
 .../apache/atlas/web/resources/BaseService.java | 126 ++++++
 .../web/resources/CatalogExceptionMapper.java   |  62 +++
 .../CatalogRuntimeExceptionMapper.java          |  78 ++++
 .../atlas/web/resources/EntityService.java      | 147 ++++++
 .../atlas/web/resources/TaxonomyService.java    | 201 +++++++++
 webapp/src/main/webapp/WEB-INF/web.xml          |   5 +
 .../authorize/AtlasAuthorizationUtilsTest.java  | 121 +++++
 92 files changed, 8500 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/pom.xml
----------------------------------------------------------------------
diff --git a/catalog/pom.xml b/catalog/pom.xml
new file mode 100755
index 0000000..8a49d3d
--- /dev/null
+++ b/catalog/pom.xml
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  ~ 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.
+  -->
+
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.atlas</groupId>
+        <artifactId>apache-atlas</artifactId>
+        <version>0.7-incubating-SNAPSHOT</version>
+    </parent>
+    <artifactId>atlas-catalog</artifactId>
+    <description>Apache Atlas Business Catalog Module</description>
+    <name>Apache Atlas Business Catalog</name>
+    <packaging>jar</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.atlas</groupId>
+            <artifactId>atlas-repository</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.atlas</groupId>
+            <artifactId>atlas-typesystem</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.atlas</groupId>
+            <artifactId>atlas-server-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>joda-time</groupId>
+            <artifactId>joda-time</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.google.inject</groupId>
+            <artifactId>guice</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.google.inject.extensions</groupId>
+            <artifactId>guice-throwingproviders</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.google.inject.extensions</groupId>
+            <artifactId>guice-multibindings</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.googlecode.json-simple</groupId>
+            <artifactId>json-simple</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.tinkerpop.blueprints</groupId>
+            <artifactId>blueprints-core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.tinkerpop.gremlin</groupId>
+            <artifactId>gremlin-java</artifactId>
+        </dependency>
+
+        <!-- testing -->
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymock</artifactId>
+            <version>3.4</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.testng</groupId>
+            <artifactId>testng</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>2.4</version>
+                <configuration>
+                    <excludes>
+                        <exclude>**/log4j.xml</exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/AtlasTypeSystem.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/AtlasTypeSystem.java b/catalog/src/main/java/org/apache/atlas/catalog/AtlasTypeSystem.java
new file mode 100644
index 0000000..6f2e0be
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/AtlasTypeSystem.java
@@ -0,0 +1,79 @@
+/**
+ * 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.catalog;
+
+import org.apache.atlas.catalog.definition.ResourceDefinition;
+import org.apache.atlas.catalog.exception.ResourceAlreadyExistsException;
+
+import java.util.Map;
+
+/**
+ * Abstraction for Atlas Type System.
+ */
+public interface AtlasTypeSystem {
+
+    /**
+     * Create a Type in the Atlas Type System if it doesn't already exist.
+     * If the type already exists, this method has no affect.
+     *
+     * @param resourceDefinition  resource definition for type being created
+     * @param name                type name
+     * @param description         description of the type being created
+     *
+     * @throws ResourceAlreadyExistsException if entity already exists
+     */
+    void createClassType(ResourceDefinition resourceDefinition, String name, String description)
+            throws ResourceAlreadyExistsException;
+
+    /**
+     * Create an entity in the Atlas Type System for the provided request and resource definition.
+     * If Type associated with the entity doesn't already exist, it is created.
+     *
+     * @param definition the definition of the resource for which we are creating the entity
+     * @param request    the user request
+     *
+     * @throws ResourceAlreadyExistsException if type already exists
+     */
+    void createEntity(ResourceDefinition definition, Request request)
+            throws ResourceAlreadyExistsException;
+
+    /**
+     * Create a trait instance instance in the Atlas Type System.
+     *
+     * @param resourceDefinition  resource definition for trait type being created
+     * @param name                type name
+     * @param description         description of the type being created
+     *
+     * @throws ResourceAlreadyExistsException if type already exists
+     */
+    void createTraitType(ResourceDefinition resourceDefinition, String name, String description)
+            throws ResourceAlreadyExistsException;
+
+    /**
+     * Create a trait instance in the Atlas Type System and associate it with the entity identified by the provided guid.
+     *
+     * @param guid        id of the entity which will be associated with the trait instance
+     * @param typeName    type name of the trait
+     * @param properties  property map used to populate the trait instance
+     *
+     * @throws ResourceAlreadyExistsException if trait instance is already associated with the entity
+     */
+    void createTraitInstance(String guid, String typeName, Map<String, Object> properties)
+            throws ResourceAlreadyExistsException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/BaseRequest.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/BaseRequest.java b/catalog/src/main/java/org/apache/atlas/catalog/BaseRequest.java
new file mode 100644
index 0000000..f3376b0
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/BaseRequest.java
@@ -0,0 +1,62 @@
+/**
+ * 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.catalog;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+
+/**
+ * Base user API request.
+ */
+public abstract class BaseRequest implements Request {
+    private final Map<String, Object> properties = new HashMap<>();
+    private final String queryString;
+    private final Collection<String> additionalSelectProperties = new HashSet<>();
+
+    protected BaseRequest(Map<String, Object> properties, String queryString) {
+        if (properties != null) {
+            this.properties.putAll((properties));
+        }
+        this.queryString = queryString;
+    }
+
+    public Map<String, Object> getProperties() {
+        return properties;
+    }
+
+    public <T> T getProperty(String name) {
+        return (T)properties.get(name);
+    }
+
+    public String getQueryString() {
+        return queryString;
+    }
+
+    @Override
+    public void addAdditionalSelectProperties(Collection<String> resultProperties) {
+        additionalSelectProperties.addAll(resultProperties);
+    }
+
+    @Override
+    public Collection<String> getAdditionalSelectProperties() {
+        return additionalSelectProperties;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/BaseResourceProvider.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/BaseResourceProvider.java b/catalog/src/main/java/org/apache/atlas/catalog/BaseResourceProvider.java
new file mode 100644
index 0000000..517eaf6
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/BaseResourceProvider.java
@@ -0,0 +1,40 @@
+/**
+ * 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.catalog;
+
+import org.apache.atlas.catalog.definition.ResourceDefinition;
+import org.apache.atlas.catalog.query.QueryFactory;
+
+import java.util.*;
+
+/**
+ * Base class for resource providers.
+ */
+public abstract class BaseResourceProvider implements ResourceProvider {
+    protected AtlasTypeSystem typeSystem;
+    protected QueryFactory queryFactory = new QueryFactory();
+
+    protected BaseResourceProvider(AtlasTypeSystem typeSystem) {
+        this.typeSystem = typeSystem;
+    }
+
+    protected void setQueryFactory(QueryFactory factory) {
+        queryFactory = factory;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/CollectionRequest.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/CollectionRequest.java b/catalog/src/main/java/org/apache/atlas/catalog/CollectionRequest.java
new file mode 100644
index 0000000..b1be1ae
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/CollectionRequest.java
@@ -0,0 +1,35 @@
+/**
+ * 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.catalog;
+
+import java.util.Map;
+
+/**
+ * A request for a collection resource.
+ */
+public class CollectionRequest extends BaseRequest {
+    public CollectionRequest(Map<String, Object> properties, String queryString) {
+        super(properties, queryString);
+    }
+
+    @Override
+    public Cardinality getCardinality() {
+        return Cardinality.COLLECTION;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/DefaultDateFormatter.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/DefaultDateFormatter.java b/catalog/src/main/java/org/apache/atlas/catalog/DefaultDateFormatter.java
new file mode 100644
index 0000000..df07505
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/DefaultDateFormatter.java
@@ -0,0 +1,39 @@
+/**
+ * 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.catalog;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+
+/**
+ * Format a date field which is represented as a long.
+ */
+public class DefaultDateFormatter implements PropertyValueFormatter<Long, String> {
+
+    //todo: obtain format from atlas proper
+    public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd:HH:mm:ss");
+
+    @Override
+    public String format(Long l) {
+        Calendar calendar = new GregorianCalendar();
+        calendar.setTimeInMillis(l);
+        return DATE_FORMAT.format(calendar.getTime());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/DefaultPropertyMapper.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/DefaultPropertyMapper.java b/catalog/src/main/java/org/apache/atlas/catalog/DefaultPropertyMapper.java
new file mode 100644
index 0000000..2f52b3b
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/DefaultPropertyMapper.java
@@ -0,0 +1,142 @@
+/**
+ * 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.catalog;
+
+import org.apache.atlas.AtlasException;
+import org.apache.atlas.catalog.exception.CatalogRuntimeException;
+import org.apache.atlas.repository.Constants;
+import org.apache.atlas.typesystem.types.FieldMapping;
+import org.apache.atlas.typesystem.types.HierarchicalType;
+import org.apache.atlas.typesystem.types.TypeSystem;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Default property mapper which translates property names to/from name exposed in API to internal fully qualified name.
+ */
+public class DefaultPropertyMapper implements PropertyMapper {
+    //todo: abstract HierarchicalType
+    private Map<String, HierarchicalType> typeInstances = new HashMap<>();
+    private final Map<String, String> m_qualifiedToCleanMap = new HashMap<>();
+    private final Map<String, String> m_cleanToQualifiedMap = new HashMap<>();
+
+
+    public DefaultPropertyMapper() {
+        this(Collections.<String, String>emptyMap(), Collections.<String, String>emptyMap());
+    }
+
+    public DefaultPropertyMapper(Map<String, String> qualifiedToCleanMap,
+                                 Map<String, String> cleanToQualifiedMap) {
+        setDefaultMappings();
+
+        m_qualifiedToCleanMap.putAll(qualifiedToCleanMap);
+        m_cleanToQualifiedMap.putAll(cleanToQualifiedMap);
+    }
+
+    @Override
+    public String toCleanName(String propName, String type) {
+        HierarchicalType dataType = getDataType(type);
+        String replacement = m_qualifiedToCleanMap.get(propName);
+        if (replacement == null && dataType != null) {
+            FieldMapping fieldMap = dataType.fieldMapping();
+            if (! fieldMap.fields.containsKey(propName) && propName.contains(".")) {
+                String cleanName = propName.substring(propName.lastIndexOf('.') + 1);
+                if (fieldMap.fields.containsKey(cleanName)) {
+                    replacement = cleanName;
+                }
+            }
+        }
+
+        if (replacement == null) {
+            replacement = propName;
+        }
+        return replacement;
+    }
+
+    @Override
+    public String toFullyQualifiedName(String propName, String type) {
+        HierarchicalType dataType = getDataType(type);
+        String replacement = m_cleanToQualifiedMap.get(propName);
+        if (replacement == null && dataType != null) {
+            FieldMapping fieldMap = dataType.fieldMapping();
+            if (fieldMap.fields.containsKey(propName)) {
+                try {
+                    replacement = dataType.getQualifiedName(propName);
+                } catch (AtlasException e) {
+                    throw new CatalogRuntimeException(String.format(
+                            "Unable to resolve fully qualified property name for type '%s': %s", type, e), e);
+                }
+            }
+        }
+
+        if (replacement == null) {
+            replacement = propName;
+        }
+        return replacement;
+    }
+
+    //todo: abstract this via AtlasTypeSystem
+    protected synchronized HierarchicalType getDataType(String type) {
+        HierarchicalType dataType = typeInstances.get(type);
+        //todo: are there still cases where type can be null?
+        if (dataType == null) {
+            dataType = createDataType(type);
+            typeInstances.put(type, dataType);
+        }
+        return dataType;
+    }
+
+    protected HierarchicalType createDataType(String type) {
+        try {
+            return TypeSystem.getInstance().getDataType(HierarchicalType.class, type);
+        } catch (AtlasException e) {
+            throw new CatalogRuntimeException("Unable to get type instance from type system for type: " + type, e);
+        }
+    }
+
+    private void setDefaultMappings() {
+        //todo: these are all internal "__*" properties
+        //todo: should be able to ask type system for the "clean" name for these
+        m_qualifiedToCleanMap.put(Constants.GUID_PROPERTY_KEY, "id");
+        m_cleanToQualifiedMap.put("id", Constants.GUID_PROPERTY_KEY);
+
+        m_qualifiedToCleanMap.put(Constants.TIMESTAMP_PROPERTY_KEY, "creation_time");
+        m_cleanToQualifiedMap.put("creation_time", Constants.TIMESTAMP_PROPERTY_KEY);
+
+        m_qualifiedToCleanMap.put(Constants.MODIFICATION_TIMESTAMP_PROPERTY_KEY, "modified_time");
+        m_cleanToQualifiedMap.put("modified_time", Constants.MODIFICATION_TIMESTAMP_PROPERTY_KEY);
+
+        m_qualifiedToCleanMap.put(Constants.ENTITY_TYPE_PROPERTY_KEY, "type");
+        m_cleanToQualifiedMap.put("type", Constants.ENTITY_TYPE_PROPERTY_KEY);
+
+        m_qualifiedToCleanMap.put(Constants.VERSION_PROPERTY_KEY, "version");
+        m_cleanToQualifiedMap.put("version", Constants.VERSION_PROPERTY_KEY);
+
+        m_qualifiedToCleanMap.put(Constants.TRAIT_NAMES_PROPERTY_KEY, "trait_names");
+        m_cleanToQualifiedMap.put("trait_names", Constants.TRAIT_NAMES_PROPERTY_KEY);
+
+        m_qualifiedToCleanMap.put(Constants.SUPER_TYPES_PROPERTY_KEY, "super_types");
+        m_cleanToQualifiedMap.put("super_types", Constants.SUPER_TYPES_PROPERTY_KEY);
+
+        m_qualifiedToCleanMap.put(Constants.STATE_PROPERTY_KEY, "state");
+        m_cleanToQualifiedMap.put("state", Constants.STATE_PROPERTY_KEY);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/DefaultTypeSystem.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/DefaultTypeSystem.java b/catalog/src/main/java/org/apache/atlas/catalog/DefaultTypeSystem.java
new file mode 100644
index 0000000..f71c061
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/DefaultTypeSystem.java
@@ -0,0 +1,130 @@
+/**
+ * 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.catalog;
+
+import org.apache.atlas.AtlasException;
+import org.apache.atlas.catalog.definition.ResourceDefinition;
+import org.apache.atlas.catalog.exception.CatalogRuntimeException;
+import org.apache.atlas.catalog.exception.ResourceAlreadyExistsException;
+import org.apache.atlas.services.MetadataService;
+import org.apache.atlas.typesystem.ITypedReferenceableInstance;
+import org.apache.atlas.typesystem.Referenceable;
+import org.apache.atlas.typesystem.Struct;
+import org.apache.atlas.typesystem.exception.EntityExistsException;
+import org.apache.atlas.typesystem.exception.TypeExistsException;
+import org.apache.atlas.typesystem.json.TypesSerialization;
+import org.apache.atlas.typesystem.types.*;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * Default implementation.
+ */
+public class DefaultTypeSystem implements AtlasTypeSystem {
+    private final MetadataService metadataService;
+
+    /**
+     * Constructor.
+     *
+     * @param metadataService  atlas metadata service
+     */
+    public DefaultTypeSystem(MetadataService metadataService) {
+        this.metadataService = metadataService;
+    }
+
+    @Override
+    public void createEntity(ResourceDefinition definition, Request request) throws ResourceAlreadyExistsException {
+        String typeName = definition.getTypeName();
+        try {
+            createClassType(definition, typeName, typeName + " Definition");
+        } catch (ResourceAlreadyExistsException e) {
+            // ok if type already exists
+        }
+        try {
+            Referenceable entity = new Referenceable(typeName, request.getProperties());
+            ITypedReferenceableInstance typedInstance = metadataService.getTypedReferenceableInstance(entity);
+            metadataService.createEntities(Collections.singletonList(typedInstance).toArray(new ITypedReferenceableInstance[1]));
+        } catch (EntityExistsException e) {
+            throw new ResourceAlreadyExistsException(
+                    "Attempted to create an entity which already exists: " + request.getProperties());
+        } catch (AtlasException e) {
+            throw new CatalogRuntimeException("An expected exception occurred creating an entity: " + e, e);
+        }
+    }
+
+    @Override
+    public void createClassType(ResourceDefinition resourceDefinition, String name, String description)
+            throws ResourceAlreadyExistsException {
+
+        createType(resourceDefinition.getPropertyDefinitions(), ClassType.class, name, description, false);
+    }
+
+    @Override
+    public void createTraitType(ResourceDefinition resourceDefinition, String name, String description)
+            throws ResourceAlreadyExistsException {
+
+        createType(resourceDefinition.getPropertyDefinitions(), TraitType.class, name, description, true);
+    }
+
+    public void createTraitInstance(String guid, String typeName, Map<String, Object> properties)
+            throws ResourceAlreadyExistsException {
+
+        try {
+            // not using the constructor with properties argument because it is marked 'InterfaceAudience.Private'
+            Struct struct = new Struct(typeName);
+            for (Map.Entry<String, Object> propEntry : properties.entrySet()) {
+                struct.set(propEntry.getKey(), propEntry.getValue());
+            }
+            metadataService.addTrait(guid, metadataService.createTraitInstance(struct));
+        } catch (IllegalArgumentException e) {
+            //todo: unfortunately, IllegalArgumentException can be thrown for other reasons
+            if (e.getMessage().contains("is already defined for entity")) {
+                throw new ResourceAlreadyExistsException(
+                        String.format("Tag '%s' already associated with the entity", typeName));
+            } else {
+                throw e;
+            }
+        } catch (AtlasException e) {
+            throw new CatalogRuntimeException(String.format(
+                    "Unable to create trait instance '%s' in type system: %s", typeName, e), e);
+        }
+    }
+
+    private <T extends HierarchicalType> void createType(Collection<AttributeDefinition> attributes,
+                                                         Class<T> type,
+                                                         String name,
+                                                         String description,
+                                                         boolean isTrait)
+                                                         throws ResourceAlreadyExistsException {
+
+        try {
+            HierarchicalTypeDefinition<T> definition = new HierarchicalTypeDefinition<>(type, name, description, null,
+                    attributes.toArray(new AttributeDefinition[attributes.size()]));
+
+            metadataService.createType(TypesSerialization.toJson(definition, isTrait));
+        } catch (TypeExistsException e) {
+            throw new ResourceAlreadyExistsException(String.format("Type '%s' already exists", name));
+        } catch (AtlasException e) {
+            throw new CatalogRuntimeException(String.format(
+                    "Unable to create type '%s' in type system: %s", name, e), e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/EntityResourceProvider.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/EntityResourceProvider.java b/catalog/src/main/java/org/apache/atlas/catalog/EntityResourceProvider.java
new file mode 100644
index 0000000..c8d6f68
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/EntityResourceProvider.java
@@ -0,0 +1,72 @@
+/**
+ * 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.catalog;
+
+import org.apache.atlas.catalog.definition.EntityResourceDefinition;
+import org.apache.atlas.catalog.definition.ResourceDefinition;
+import org.apache.atlas.catalog.exception.*;
+import org.apache.atlas.catalog.query.AtlasQuery;
+
+import java.util.*;
+
+/**
+ * Provider for entity resources.
+ */
+public class EntityResourceProvider extends BaseResourceProvider implements ResourceProvider {
+    private final static ResourceDefinition resourceDefinition = new EntityResourceDefinition();
+
+    public EntityResourceProvider(AtlasTypeSystem typeSystem) {
+        super(typeSystem);
+    }
+
+    @Override
+    public Result getResourceById(Request request) throws ResourceNotFoundException {
+        AtlasQuery atlasQuery;
+        try {
+            atlasQuery = queryFactory.createEntityQuery(request);
+        } catch (InvalidQueryException e) {
+            throw new CatalogRuntimeException("Unable to compile internal Entity query: " + e, e);
+        }
+        Collection<Map<String, Object>> results = atlasQuery.execute();
+        if (results.isEmpty()) {
+            throw new ResourceNotFoundException(String.format("Entity '%s' not found.",
+                    request.getProperty(resourceDefinition.getIdPropertyName())));
+        }
+        return new Result(results);
+    }
+
+    @Override
+    public Result getResources(Request request) throws InvalidQueryException, ResourceNotFoundException {
+        AtlasQuery atlasQuery = queryFactory.createEntityQuery(request);
+        return new Result(atlasQuery.execute());
+    }
+
+    @Override
+    public void createResource(Request request)
+            throws InvalidPayloadException, ResourceAlreadyExistsException, ResourceNotFoundException {
+
+        // creation of entities is currently unsupported
+        throw new UnsupportedOperationException("Creation of entities is not currently supported");
+    }
+
+    @Override
+    public Collection<String> createResources(Request request) throws InvalidQueryException, ResourceNotFoundException {
+        throw new UnsupportedOperationException("Creation of entities is not currently supported");
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/EntityTagResourceProvider.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/EntityTagResourceProvider.java b/catalog/src/main/java/org/apache/atlas/catalog/EntityTagResourceProvider.java
new file mode 100644
index 0000000..dc4ab0d
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/EntityTagResourceProvider.java
@@ -0,0 +1,135 @@
+/**
+ * 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.catalog;
+
+import org.apache.atlas.catalog.definition.EntityTagResourceDefinition;
+import org.apache.atlas.catalog.definition.ResourceDefinition;
+import org.apache.atlas.catalog.exception.*;
+import org.apache.atlas.catalog.query.AtlasQuery;
+
+import java.util.*;
+
+/**
+ * Provider for entity tag resources.
+ */
+public class EntityTagResourceProvider extends BaseResourceProvider implements ResourceProvider {
+    private final static ResourceDefinition resourceDefinition = new EntityTagResourceDefinition();
+    private TermResourceProvider termResourceProvider;
+
+    public EntityTagResourceProvider(AtlasTypeSystem typeSystem) {
+        super(typeSystem);
+
+    }
+
+    @Override
+    public Result getResourceById(Request request) throws ResourceNotFoundException {
+        AtlasQuery atlasQuery;
+        try {
+            atlasQuery = queryFactory.createEntityTagQuery(request);
+        } catch (InvalidQueryException e) {
+            throw new CatalogRuntimeException("Unable to compile internal Entity Tag query: " + e, e);
+        }
+        Collection<Map<String, Object>> results = atlasQuery.execute();
+        if (results.isEmpty()) {
+            throw new ResourceNotFoundException(String.format("Tag '%s' not found.",
+                    request.getProperty(resourceDefinition.getIdPropertyName())));
+        }
+
+        return new Result(results);
+    }
+
+    @Override
+    public Result getResources(Request request) throws InvalidQueryException, ResourceNotFoundException {
+        AtlasQuery atlasQuery = queryFactory.createEntityTagQuery(request);
+        return new Result(atlasQuery.execute());
+    }
+
+    @Override
+    public void createResource(Request request)
+            throws InvalidPayloadException, ResourceAlreadyExistsException, ResourceNotFoundException {
+
+        String entityId = String.valueOf(request.getProperties().remove("id"));
+        resourceDefinition.validate(request);
+        Result termResult = getTermQueryResult(request.<String>getProperty("name"));
+        Map<String, Object> termProperties = termResult.getPropertyMaps().iterator().next();
+        //todo: use constant for property name
+        if (String.valueOf(termProperties.get("available_as_tag")).equals("false")) {
+            throw new InvalidPayloadException(
+                    "Attempted to tag an entity with a term which is not available to be tagged");
+        }
+        tagEntities(Collections.singleton(entityId), termProperties);
+    }
+
+    //todo: response for case mixed case where some subset of creations fail
+    @Override
+    public Collection<String> createResources(Request request)
+            throws InvalidQueryException, ResourceNotFoundException, ResourceAlreadyExistsException {
+
+        Collection<String> relativeUrls = new ArrayList<>();
+        AtlasQuery atlasQuery = queryFactory.createEntityQuery(request);
+        Collection<String> guids = new ArrayList<>();
+        for (Map<String, Object> entityMap: atlasQuery.execute()) {
+            guids.add(String.valueOf(entityMap.get("id")));
+        }
+
+        Collection<Map<String, String>> tagMaps = request.getProperty("tags");
+        for (Map<String, String> tagMap : tagMaps) {
+            Result termResult = getTermQueryResult(tagMap.get("name"));
+            relativeUrls.addAll(tagEntities(guids, termResult.getPropertyMaps().iterator().next()));
+        }
+        return relativeUrls;
+    }
+
+    private Result getTermQueryResult(String termName) throws ResourceNotFoundException {
+        Request tagRequest = new InstanceRequest(
+                Collections.<String, Object>singletonMap("termPath", new TermPath(termName)));
+
+        tagRequest.addAdditionalSelectProperties(Collections.singleton("type"));
+        return getTermResourceProvider().getResourceById(tagRequest);
+    }
+
+    private Collection<String> tagEntities(Collection<String> entityGuids, Map<String, Object> termProperties)
+            throws ResourceAlreadyExistsException {
+
+        Collection<String> relativeUrls = new ArrayList<>();
+        for (String guid : entityGuids) {
+            //createTermEdge(entity, Collections.singleton(termVertex));
+            // copy term properties from trait associated with taxonomy to be set
+            // on trait associated with new entity (basically clone at time of tag event)
+            //todo: any changes to 'singleton' trait won't be reflected in new trait
+            //todo: iterate over properties in term definition instead of hard coding here
+            Map<String, Object> properties = new HashMap<>();
+            String termName = String.valueOf(termProperties.get("name"));
+            properties.put("name", termName);
+            properties.put("description", termProperties.get("description"));
+
+            typeSystem.createTraitInstance(guid, termName, properties);
+            //todo: *** shouldn't know anything about href structure in this class ***
+            relativeUrls.add(String.format("v1/entities/%s/tags/%s", guid, termName));
+        }
+        return relativeUrls;
+    }
+
+    protected synchronized ResourceProvider getTermResourceProvider() {
+        if (termResourceProvider == null) {
+            termResourceProvider = new TermResourceProvider(typeSystem);
+        }
+        return termResourceProvider;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/InstanceRequest.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/InstanceRequest.java b/catalog/src/main/java/org/apache/atlas/catalog/InstanceRequest.java
new file mode 100644
index 0000000..01583c4
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/InstanceRequest.java
@@ -0,0 +1,35 @@
+/**
+ * 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.catalog;
+
+import java.util.Map;
+
+/**
+ * A request for an instance resource.
+ */
+public class InstanceRequest extends BaseRequest {
+    public InstanceRequest(Map<String, Object> properties) {
+        super(properties, null);
+    }
+
+    @Override
+    public Cardinality getCardinality() {
+        return Cardinality.INSTANCE;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/JsonSerializer.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/JsonSerializer.java b/catalog/src/main/java/org/apache/atlas/catalog/JsonSerializer.java
new file mode 100644
index 0000000..a75639f
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/JsonSerializer.java
@@ -0,0 +1,90 @@
+/**
+ * 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.catalog;
+
+import com.google.gson.stream.JsonWriter;
+import org.apache.atlas.catalog.exception.CatalogRuntimeException;
+
+import javax.ws.rs.core.UriInfo;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * JSON serializer.
+ */
+public class JsonSerializer {
+    public String serialize(Result result, UriInfo ui) {
+        Writer json = new StringWriter();
+        JsonWriter writer = new JsonWriter(json);
+        writer.setIndent("    ");
+
+        try {
+            writeValue(writer, result.getPropertyMaps(), ui.getBaseUri().toASCIIString());
+        } catch (IOException e) {
+            throw new CatalogRuntimeException("Unable to write JSON response.", e);
+        }
+        return json.toString();
+    }
+
+    private void writeValue(JsonWriter writer, Object value, String baseUrl) throws IOException {
+        if (value == null) {
+            writer.nullValue();
+        } else if (value instanceof Map) {
+            writer.beginObject();
+            LinkedHashMap<String, Object> nonScalarMap = new LinkedHashMap<>();
+            for (Map.Entry<String, Object> entry : ((Map<String, Object>) value).entrySet()) {
+                String key = entry.getKey();
+                Object val = entry.getValue();
+
+                if (val == null || ! (val instanceof Collection || val instanceof Map)) {
+                    //todo: use a token in value instead of prop name
+                    if (key.equals("href")) {
+                        val = baseUrl + String.valueOf(val);
+                    }
+                    writer.name(key);
+                    writeValue(writer, val, baseUrl);
+                } else {
+                    nonScalarMap.put(key, val);
+                }
+            }
+            for (Map.Entry<String, Object> entry : nonScalarMap.entrySet()) {
+                writer.name(entry.getKey());
+                writeValue(writer, entry.getValue(), baseUrl);
+            }
+            writer.endObject();
+        } else if (value instanceof Collection) {
+            writer.beginArray();
+            for (Object o : (Collection) value) {
+                writeValue(writer, o, baseUrl);
+            }
+            writer.endArray();
+        } else if (value instanceof Number) {
+            writer.value((Number) value);
+        } else if (value instanceof Boolean) {
+            writer.value((Boolean) value);
+        } else {
+            // everything else is String
+            writer.value(String.valueOf(value));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/PropertyMapper.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/PropertyMapper.java b/catalog/src/main/java/org/apache/atlas/catalog/PropertyMapper.java
new file mode 100644
index 0000000..50ee275
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/PropertyMapper.java
@@ -0,0 +1,45 @@
+/**
+ * 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.catalog;
+
+
+/**
+ * Translates property names to/from name exposed in API to internal fully qualified name.
+ */
+public interface PropertyMapper {
+    /**
+     * Translate a qualified name to a clean name.
+     *
+     * @param propName  property name to translate
+     * @param type  resource type
+     *
+     * @return  clean property name
+     */
+    String toCleanName(String propName, String type);
+
+    /**
+     * Translate a clean name to a fully qualified name.
+     *
+     * @param propName  property name to translate
+     * @param type  resource type
+     *
+     * @return fully qualified property name
+     */
+    String toFullyQualifiedName(String propName, String type);
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/PropertyValueFormatter.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/PropertyValueFormatter.java b/catalog/src/main/java/org/apache/atlas/catalog/PropertyValueFormatter.java
new file mode 100644
index 0000000..a42f528
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/PropertyValueFormatter.java
@@ -0,0 +1,33 @@
+/**
+ * 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.catalog;
+
+/**
+ * A rule for translating a property value.
+ */
+public interface PropertyValueFormatter <T,V> {
+    /**
+     * Format a property value.
+     *
+     * @param value  property value to format
+     *
+     * @return  formatted property value
+     */
+    V format(T value);
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/Request.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/Request.java b/catalog/src/main/java/org/apache/atlas/catalog/Request.java
new file mode 100644
index 0000000..7dc781a
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/Request.java
@@ -0,0 +1,77 @@
+/**
+ * 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.catalog;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * Represents a user request.
+ */
+public interface Request {
+    /**
+     * Request cardinality enum.
+     */
+    enum Cardinality {INSTANCE, COLLECTION}
+
+    /**
+     * Get request properties.
+     *
+     * @return request property map
+     */
+    Map<String, Object> getProperties();
+
+    /**
+     * Get the value of a specified property.
+     *
+     * @param name  property name
+     * @param <T>   value type
+     *
+     * @return value for the requested property or null if property not in map
+     */
+    <T> T getProperty(String name);
+
+    /**
+     * Get the query string.
+     *
+     * @return the user specified query string or null
+     */
+    String getQueryString();
+
+    /**
+     * Get the cardinality of the request.
+     *
+     * @return the request cardinality
+     */
+    Cardinality getCardinality();
+
+    /**
+     * Add additional property names which should be returned in the result.
+     *
+     * @param resultProperties  collection of property names
+     */
+    void addAdditionalSelectProperties(Collection<String> resultProperties);
+
+    /**
+     * Get any additional property names which should be included in the result.
+     *
+     * @return collection of added property names or an empty collection
+     */
+    Collection<String> getAdditionalSelectProperties();
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/ResourceComparator.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/ResourceComparator.java b/catalog/src/main/java/org/apache/atlas/catalog/ResourceComparator.java
new file mode 100644
index 0000000..deb2e4c
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/ResourceComparator.java
@@ -0,0 +1,62 @@
+/**
+ * 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.catalog;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * Provides key ordering for resource property maps.
+ * Ordering can be defined explicitly for specific properties,
+ * otherwise natural ordering is used.
+ */
+public class ResourceComparator implements Comparator<String> {
+    private static List<String> ordering = new ArrayList<>();
+
+    @Override
+    public int compare(String s1, String s2) {
+       if (s1.equals(s2)) {
+            return 0;
+        }
+
+        int s1Order = ordering.indexOf(s1);
+        int s2Order = ordering.indexOf(s2);
+
+        if (s1Order == -1 && s2Order == -1) {
+            return s1.compareTo(s2);
+        }
+
+        if (s1Order != -1 && s2Order != -1) {
+            return s1Order - s2Order;
+        }
+
+        return s1Order == -1 ? 1 : -1;
+
+    }
+
+    //todo: each resource definition can provide its own ordering list
+    static {
+        ordering.add("href");
+        ordering.add("name");
+        ordering.add("id");
+        ordering.add("description");
+        ordering.add("type");
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/ResourceProvider.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/ResourceProvider.java b/catalog/src/main/java/org/apache/atlas/catalog/ResourceProvider.java
new file mode 100644
index 0000000..4c4319c
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/ResourceProvider.java
@@ -0,0 +1,75 @@
+/**
+ * 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.catalog;
+
+import org.apache.atlas.catalog.exception.*;
+
+import java.util.Collection;
+
+/**
+ * Provider for a resource type.
+ */
+public interface ResourceProvider {
+    /**
+     * Get a resource by primary key.
+     *
+     * @param request  request instance which contains the required id properties and no query string
+     * @return  result containing the requested resource; never null
+     *
+     * @throws ResourceNotFoundException if the requested resource isn't found
+     */
+    Result getResourceById(Request request) throws ResourceNotFoundException;
+
+    /**
+     * Get all resources which match the provider query.
+     *
+     * @param request request instance which will include a query string and possibly properties
+     * @return result containing collection of matching resources. If no resources match
+     *         a result is returned with no resources
+     *
+     * @throws InvalidQueryException     if the user query contains invalid syntax
+     * @throws ResourceNotFoundException if a parent resource of the requested resource doesn't exist
+     */
+    Result getResources(Request request) throws InvalidQueryException, ResourceNotFoundException;
+
+    /**
+     * Create a single resource.
+     *
+     * @param request request instance containing the contents of the resource to create
+     *
+     * @throws InvalidPayloadException        if the payload or any other part of the user request is invalid
+     * @throws ResourceAlreadyExistsException if the resource already exists
+     * @throws ResourceNotFoundException      if a parent of the resource to create doesn't exist
+     */
+    void createResource(Request request)
+            throws InvalidPayloadException, ResourceAlreadyExistsException, ResourceNotFoundException;
+
+    //todo: define the behavior for partial success
+    /**
+     * Create multiple resources.
+     *
+     * @param request  request instance containing the contents of 1..n resources
+     * @return collection of relative urls for the created resources
+     *
+     * @throws InvalidPayloadException        if the payload or any other part of the user request is invalid
+     * @throws ResourceAlreadyExistsException if the resource already exists
+     * @throws ResourceNotFoundException      if a parent of the resource to create doesn't exist
+     */
+    Collection<String> createResources(Request request) throws CatalogException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/Result.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/Result.java b/catalog/src/main/java/org/apache/atlas/catalog/Result.java
new file mode 100644
index 0000000..34a81ab
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/Result.java
@@ -0,0 +1,50 @@
+/**
+ * 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.catalog;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * Resource provider result.
+ */
+public class Result {
+    /**
+     * collection of property maps
+     */
+    private Collection<Map<String, Object>> propertyMaps;
+
+    /**
+     * Constructor.
+     *
+     * @param propertyMaps collection of property maps
+     */
+    public Result(Collection<Map<String, Object>> propertyMaps) {
+        this.propertyMaps = propertyMaps;
+    }
+
+    /**
+     * Obtain the result property maps.
+     *
+     * @return result property maps
+     */
+    public Collection<Map<String, Object>> getPropertyMaps() {
+        return propertyMaps;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/TaxonomyResourceProvider.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/TaxonomyResourceProvider.java b/catalog/src/main/java/org/apache/atlas/catalog/TaxonomyResourceProvider.java
new file mode 100644
index 0000000..7a46f5d
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/TaxonomyResourceProvider.java
@@ -0,0 +1,80 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <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.catalog;
+
+import org.apache.atlas.catalog.definition.ResourceDefinition;
+import org.apache.atlas.catalog.definition.TaxonomyResourceDefinition;
+import org.apache.atlas.catalog.exception.*;
+import org.apache.atlas.catalog.query.AtlasQuery;
+
+import java.util.*;
+
+/**
+ * Provider for taxonomy resources.
+ */
+public class TaxonomyResourceProvider extends BaseResourceProvider implements ResourceProvider {
+    private static final ResourceDefinition resourceDefinition = new TaxonomyResourceDefinition();
+    public TaxonomyResourceProvider(AtlasTypeSystem typeSystem) {
+        super(typeSystem);
+    }
+
+    @Override
+    public Result getResourceById(Request request) throws ResourceNotFoundException {
+        AtlasQuery atlasQuery;
+        try {
+            atlasQuery = queryFactory.createTaxonomyQuery(request);
+        } catch (InvalidQueryException e) {
+            throw new CatalogRuntimeException("Unable to compile internal Taxonomy query: " + e, e);
+        }
+        Collection<Map<String, Object>> results = atlasQuery.execute();
+        if (results.isEmpty()) {
+            throw new ResourceNotFoundException(String.format("Taxonomy '%s' not found.",
+                    request.getProperty(resourceDefinition.getIdPropertyName())));
+        }
+        return new Result(results);
+    }
+
+    public Result getResources(Request request) throws InvalidQueryException, ResourceNotFoundException {
+        AtlasQuery atlasQuery = queryFactory.createTaxonomyQuery(request);
+        return new Result(atlasQuery.execute());
+    }
+
+    public synchronized void createResource(Request request)
+            throws InvalidPayloadException, ResourceAlreadyExistsException {
+
+        resourceDefinition.validate(request);
+        ensureTaxonomyDoesntExist(request);
+        typeSystem.createEntity(resourceDefinition, request);
+    }
+
+    @Override
+    public Collection<String> createResources(Request request) throws InvalidQueryException, ResourceNotFoundException {
+        throw new UnsupportedOperationException("Creating multiple Taxonomies in a request is not currently supported");
+    }
+
+    private void ensureTaxonomyDoesntExist(Request request) throws ResourceAlreadyExistsException {
+        try {
+            getResourceById(request);
+            throw new ResourceAlreadyExistsException(String.format("Taxonomy '%s' already exists.",
+                    request.getProperty("name")));
+        } catch (ResourceNotFoundException e) {
+            // expected case
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/TermPath.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/TermPath.java b/catalog/src/main/java/org/apache/atlas/catalog/TermPath.java
new file mode 100644
index 0000000..3252227
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/TermPath.java
@@ -0,0 +1,111 @@
+/**
+ * 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.catalog;
+
+/**
+ * Term path information.
+ */
+//todo: split between Term and TermPath
+public class TermPath {
+    private final String m_taxonomy;
+    private final String m_fqn;
+    private final String m_name;
+    private final String[] m_paths;
+
+    public TermPath(String fullyQualifiedName) {
+        m_fqn = fullyQualifiedName;
+        //todo: validation
+        int idx = fullyQualifiedName.indexOf('.');
+        if (idx != -1) {
+            m_taxonomy = fullyQualifiedName.substring(0, idx);
+            m_name = fullyQualifiedName.substring(idx + 1);
+            m_paths = m_name.split("\\.");
+        } else {
+            m_taxonomy = fullyQualifiedName;
+            m_name = null;
+            m_paths = new String[0];
+        }
+    }
+
+    public TermPath(String taxonomyName, String termName) {
+        m_taxonomy = taxonomyName;
+        m_name = termName != null && termName.isEmpty() ? null : termName;
+
+        if (m_name != null) {
+            m_fqn = String.format("%s.%s", taxonomyName, termName);
+            m_paths = termName.split("\\.");
+        } else {
+            m_fqn = taxonomyName;
+            m_paths = new String[0];
+        }
+    }
+
+    /**
+     * Get the absolute term name which is in the form of TAXONOMY_NAME.TERM_NAME
+     *
+     * @return absolute term name which includes the taxonomy name
+     */
+    public String getFullyQualifiedName() {
+        return m_fqn;
+    }
+
+    /**
+     * Get the term name.  This differs from the absolute name in that it doesn't
+     * include the taxonomy name.
+     *
+     * @return the term name
+     */
+    public String getName() {
+        return m_name;
+    }
+
+    /**
+     * Get the short name for the term which doesn't include any taxonomy or parent information.
+     * @return term short name
+     */
+    public String getShortName() {
+        return m_paths[m_paths.length - 1];
+    }
+
+    public String getPath() {
+        if (m_name == null) {
+            return "/";
+        } else {
+            int idx = m_fqn.indexOf('.');
+            int lastIdx = m_fqn.lastIndexOf('.');
+
+            return idx == lastIdx ? "/" :
+                    m_fqn.substring(idx, lastIdx).replaceAll("\\.", "/");
+        }
+    }
+
+    public TermPath getParent() {
+        //todo: if this is the root path, throw exception
+        return new TermPath(m_taxonomy, m_name.substring(0, m_name.lastIndexOf('.')));
+    }
+
+
+    public String getTaxonomyName() {
+        return m_taxonomy;
+    }
+
+    public String[] getPathSegments() {
+        return m_paths;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/TermResourceProvider.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/TermResourceProvider.java b/catalog/src/main/java/org/apache/atlas/catalog/TermResourceProvider.java
new file mode 100644
index 0000000..431b06d
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/TermResourceProvider.java
@@ -0,0 +1,128 @@
+/**
+ * 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.catalog;
+
+import org.apache.atlas.catalog.definition.ResourceDefinition;
+import org.apache.atlas.catalog.definition.TermResourceDefinition;
+import org.apache.atlas.catalog.exception.*;
+import org.apache.atlas.catalog.query.AtlasQuery;
+
+import java.util.*;
+
+/**
+ * Provider for Term resources.
+ */
+public class TermResourceProvider extends BaseResourceProvider implements ResourceProvider {
+    private final static ResourceDefinition resourceDefinition = new TermResourceDefinition();
+    private TaxonomyResourceProvider taxonomyResourceProvider;
+
+    public TermResourceProvider(AtlasTypeSystem typeSystem) {
+        super(typeSystem);
+    }
+
+    @Override
+    public Result getResourceById(Request request) throws ResourceNotFoundException {
+        //todo: shouldn't need to add this here
+        request.getProperties().put("name", request.<TermPath>getProperty("termPath").getFullyQualifiedName());
+        AtlasQuery atlasQuery;
+        try {
+            atlasQuery = queryFactory.createTermQuery(request);
+        } catch (InvalidQueryException e) {
+            throw new CatalogRuntimeException("Unable to compile internal Term query: " + e, e);
+        }
+        Collection<Map<String, Object>> results = atlasQuery.execute();
+        if (results.isEmpty()) {
+            throw new ResourceNotFoundException(String.format("Term '%s' not found.",
+                    request.<TermPath>getProperty("termPath").getFullyQualifiedName()));
+        }
+        return new Result(results);
+    }
+
+    public Result getResources(Request request)
+            throws InvalidQueryException, ResourceNotFoundException  {
+
+        TermPath termPath = request.getProperty("termPath");
+        String queryString = doQueryStringConversions(termPath, request.getQueryString());
+        Request queryRequest = new CollectionRequest(request.getProperties(), queryString);
+        AtlasQuery atlasQuery = queryFactory.createTermQuery(queryRequest);
+        Collection<Map<String, Object>> result = atlasQuery.execute();
+        return new Result(result);
+    }
+
+    public void createResource(Request request)
+            throws InvalidPayloadException, ResourceAlreadyExistsException, ResourceNotFoundException  {
+
+        TermPath termPath = (TermPath) request.getProperties().remove("termPath");
+        String qualifiedTermName = termPath.getFullyQualifiedName();
+        request.getProperties().put("name", qualifiedTermName);
+        resourceDefinition.validate(request);
+
+        // get taxonomy
+        Request taxonomyRequest = new InstanceRequest(
+                Collections.<String, Object>singletonMap("name", termPath.getTaxonomyName()));
+        taxonomyRequest.addAdditionalSelectProperties(Collections.singleton("id"));
+        Result taxonomyResult = getTaxonomyResourceProvider().getResourceById(taxonomyRequest);
+        Map<String, Object> taxonomyPropertyMap = taxonomyResult.getPropertyMaps().iterator().next();
+
+        // ensure that parent exists if not a root level term
+        if (! termPath.getPath().equals("/")) {
+            Map<String, Object> parentProperties = new HashMap<>(request.getProperties());
+            parentProperties.put("termPath", termPath.getParent());
+            getResourceById(new InstanceRequest(parentProperties));
+        }
+
+        typeSystem.createTraitType(resourceDefinition, qualifiedTermName,
+                request.<String>getProperty("description"));
+
+        typeSystem.createTraitInstance(String.valueOf(taxonomyPropertyMap.get("id")),
+                qualifiedTermName, request.getProperties());
+    }
+
+    @Override
+    public Collection<String> createResources(Request request) throws InvalidQueryException, ResourceNotFoundException {
+        throw new UnsupportedOperationException("Creating multiple Terms in a request is not currently supported");
+    }
+
+    //todo: add generic support for pre-query modification of expected value
+    //todo: similar path parsing code is used in several places in this class
+    private String doQueryStringConversions(TermPath termPath, String queryStr) throws InvalidQueryException {
+        String hierarchyPathProp = "hierarchy/path";
+        // replace "."
+        if (queryStr != null && queryStr.contains(String.format("%s:.", hierarchyPathProp))) {
+            //todo: regular expression replacement
+            queryStr = queryStr.replaceAll(String.format("%s:.", hierarchyPathProp),
+                    String.format("%s:%s", hierarchyPathProp, termPath.getPath()));
+        }
+        return queryStr;
+    }
+
+    protected synchronized ResourceProvider getTaxonomyResourceProvider() {
+        if (taxonomyResourceProvider == null) {
+            taxonomyResourceProvider = new TaxonomyResourceProvider(typeSystem);
+        }
+        return taxonomyResourceProvider;
+    }
+}
+
+
+
+
+
+
+

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/TermVertexWrapper.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/TermVertexWrapper.java b/catalog/src/main/java/org/apache/atlas/catalog/TermVertexWrapper.java
new file mode 100644
index 0000000..d60e3f3
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/TermVertexWrapper.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
+ * <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.catalog;
+
+import com.tinkerpop.blueprints.Vertex;
+import org.apache.atlas.catalog.definition.EntityTagResourceDefinition;
+import org.apache.atlas.catalog.definition.ResourceDefinition;
+import org.apache.atlas.repository.Constants;
+
+import java.util.Collections;
+
+/**
+ * Wrapper for term vertices.
+ */
+public class TermVertexWrapper extends VertexWrapper {
+
+    public TermVertexWrapper(Vertex v) {
+        super(v, new EntityTagResourceDefinition());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/VertexWrapper.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/VertexWrapper.java b/catalog/src/main/java/org/apache/atlas/catalog/VertexWrapper.java
new file mode 100644
index 0000000..6e5d28e
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/VertexWrapper.java
@@ -0,0 +1,111 @@
+/**
+ * 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.catalog;
+
+import com.tinkerpop.blueprints.Vertex;
+import org.apache.atlas.catalog.definition.ResourceDefinition;
+import org.apache.atlas.repository.Constants;
+
+import java.util.*;
+
+/**
+ * Wrapper for vertices which provides additional information.
+ */
+public class VertexWrapper {
+    private final Vertex vertex;
+    private final String vertexType;
+    private final Set<String> removedProperties = new HashSet<>();
+    private final PropertyMapper propertyMapper;
+    private final Map<String, PropertyValueFormatter> propertyValueFormatters;
+    protected ResourceComparator resourceComparator = new ResourceComparator();
+
+    public VertexWrapper(Vertex v, ResourceDefinition resourceDefinition) {
+        this(v, resourceDefinition.getPropertyMapper(), resourceDefinition.getPropertyValueFormatters());
+    }
+
+    public VertexWrapper(Vertex v,
+                         PropertyMapper mapper,
+                         Map<String, PropertyValueFormatter> formatters) {
+        vertex = v;
+        vertexType = getVertexType(v);
+        propertyMapper = mapper;
+        propertyValueFormatters = formatters;
+    }
+
+    public Vertex getVertex() {
+        return vertex;
+    }
+
+    public <T> T getProperty(String name) {
+        T val;
+        if (removedProperties.contains(name)) {
+            val = null;
+        } else {
+            val = vertex.getProperty(propertyMapper.toFullyQualifiedName(name, vertexType));
+            if (propertyValueFormatters.containsKey(name)) {
+                //todo: fix typing of property mapper
+                val = (T) propertyValueFormatters.get(name).format(val);
+            }
+        }
+        return val;
+    }
+
+    public Collection<String> getPropertyKeys() {
+        Collection<String> propertyKeys = new TreeSet<>(resourceComparator);
+
+        for (String p : vertex.getPropertyKeys()) {
+            String cleanName = propertyMapper.toCleanName(p, vertexType);
+            if (! removedProperties.contains(cleanName)) {
+                propertyKeys.add(cleanName);
+            }
+        }
+        return propertyKeys;
+    }
+
+    public Map<String, Object> getPropertyMap() {
+        Map<String, Object> props = new TreeMap<>(resourceComparator);
+        for (String p : vertex.getPropertyKeys()) {
+            String cleanName = propertyMapper.toCleanName(p, vertexType);
+            if (! removedProperties.contains(cleanName)) {
+                Object val = vertex.getProperty(p);
+                if (propertyValueFormatters.containsKey(cleanName)) {
+                    val = propertyValueFormatters.get(cleanName).format(val);
+                }
+                props.put(cleanName, val);
+            }
+        }
+        return props;
+    }
+
+    public void removeProperty(String name) {
+        removedProperties.add(name);
+    }
+
+    public boolean isPropertyRemoved(String name) {
+        return removedProperties.contains(name);
+    }
+
+    public String toString() {
+        return String.format("VertexWrapper[name=%s]", getProperty("name"));
+    }
+
+    private String getVertexType(Vertex v) {
+        return v.getProperty(Constants.ENTITY_TYPE_PROPERTY_KEY);
+    }
+}