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:00 UTC
[4/5] incubator-atlas git commit: ATLAS-491 Business Catalog /
Taxonomy (jspeidel via yhemanth)
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/definition/BaseResourceDefinition.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/definition/BaseResourceDefinition.java b/catalog/src/main/java/org/apache/atlas/catalog/definition/BaseResourceDefinition.java
new file mode 100644
index 0000000..32d6f30
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/definition/BaseResourceDefinition.java
@@ -0,0 +1,150 @@
+/**
+ * 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.definition;
+
+import org.apache.atlas.AtlasException;
+import org.apache.atlas.catalog.*;
+import org.apache.atlas.catalog.exception.CatalogRuntimeException;
+import org.apache.atlas.catalog.exception.InvalidPayloadException;
+import org.apache.atlas.catalog.projection.Projection;
+import org.apache.atlas.catalog.projection.Relation;
+import org.apache.atlas.typesystem.types.AttributeDefinition;
+import org.apache.atlas.typesystem.types.AttributeInfo;
+import org.apache.atlas.typesystem.types.Multiplicity;
+import org.apache.atlas.typesystem.types.TypeSystem;
+
+import java.util.*;
+
+/**
+ * Base class for resource definitions.
+ */
+public abstract class BaseResourceDefinition implements ResourceDefinition {
+ protected static final TypeSystem typeSystem = TypeSystem.getInstance();
+
+ protected final Set<String> instanceProperties = new HashSet<>();
+ protected final Set<String> collectionProperties = new HashSet<>();
+ protected Map<String, AttributeDefinition> propertyDefs = new HashMap<>();
+ protected Map<String, AttributeInfo> properties = new HashMap<>();
+
+ protected final Map<String, Projection> projections = new HashMap<>();
+ protected final Map<String, Relation> relations = new HashMap<>();
+
+ protected final PropertyMapper propertyMapper;
+ protected final Map<String, PropertyValueFormatter> propertyValueFormatters = new HashMap<>();
+
+
+ public BaseResourceDefinition() {
+ DefaultDateFormatter defaultDateFormatter = new DefaultDateFormatter();
+ registerPropertyValueFormatter("creation_time", defaultDateFormatter);
+ registerPropertyValueFormatter("modified_time", defaultDateFormatter);
+
+ this.propertyMapper = createPropertyMapper();
+ }
+
+ @Override
+ public void validate(Request request) throws InvalidPayloadException {
+ Collection<String> propKeys = new HashSet<>(request.getProperties().keySet());
+ Collection<String> missingProperties = new HashSet<>();
+ for (AttributeInfo property : properties.values()) {
+ String name = property.name;
+ if (property.multiplicity == Multiplicity.REQUIRED) {
+ if (request.getProperty(name) == null) {
+ missingProperties.add(name);
+ }
+ }
+ propKeys.remove(name);
+ }
+ if (! missingProperties.isEmpty() || ! propKeys.isEmpty()) {
+ throw new InvalidPayloadException(missingProperties, propKeys);
+ }
+ //todo: property type validation
+ }
+
+ @Override
+ public Collection<AttributeDefinition> getPropertyDefinitions() {
+ return propertyDefs.values();
+ }
+
+ @Override
+ public Map<String, Object> filterProperties(Request request, Map<String, Object> propertyMap) {
+ Request.Cardinality cardinality = request.getCardinality();
+ Collection<String> requestProperties = request.getAdditionalSelectProperties();
+ Iterator<Map.Entry<String, Object>> propIter = propertyMap.entrySet().iterator();
+ while(propIter.hasNext()) {
+ Map.Entry<String, Object> propEntry = propIter.next();
+ String prop = propEntry.getKey();
+ if (! requestProperties.contains(prop)) {
+ if (cardinality == Request.Cardinality.COLLECTION) {
+ if (! collectionProperties.contains(prop)) {
+ propIter.remove();
+ }
+ } else {
+ if (! instanceProperties.isEmpty() && ! instanceProperties.contains(prop)) {
+ propIter.remove();
+ }
+ }
+ }
+ }
+ return propertyMap;
+ }
+
+ @Override
+ public Map<String, Projection> getProjections() {
+ return projections;
+ }
+
+ @Override
+ public Map<String, Relation> getRelations() {
+ return relations;
+ }
+
+
+ @Override
+ public synchronized PropertyMapper getPropertyMapper() {
+ return propertyMapper;
+ }
+
+ @Override
+ public Map<String, PropertyValueFormatter> getPropertyValueFormatters() {
+ return propertyValueFormatters;
+ }
+
+ protected void registerProperty(AttributeDefinition propertyDefinition) {
+ try {
+ propertyDefs.put(propertyDefinition.name, propertyDefinition);
+ properties.put(propertyDefinition.name, new AttributeInfo(typeSystem, propertyDefinition, null));
+ } catch (AtlasException e) {
+ throw new CatalogRuntimeException("Unable to create attribute: " + propertyDefinition.name, e);
+ }
+ }
+
+ protected void registerPropertyValueFormatter(String property, PropertyValueFormatter valueFormatter) {
+ propertyValueFormatters.put(property, valueFormatter);
+ }
+
+ /**
+ * Create a new property mapper instance.
+ * Should be overridden in children where the default implementation isn't sufficient.
+ *
+ * @return a new property mapper instance
+ */
+ protected PropertyMapper createPropertyMapper() {
+ return new DefaultPropertyMapper();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/definition/EntityResourceDefinition.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/definition/EntityResourceDefinition.java b/catalog/src/main/java/org/apache/atlas/catalog/definition/EntityResourceDefinition.java
new file mode 100644
index 0000000..cf55f1f
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/definition/EntityResourceDefinition.java
@@ -0,0 +1,120 @@
+/**
+ * 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.definition;
+
+import com.tinkerpop.pipes.PipeFunction;
+import com.tinkerpop.pipes.transform.TransformFunctionPipe;
+import org.apache.atlas.catalog.Request;
+import org.apache.atlas.catalog.exception.InvalidPayloadException;
+import org.apache.atlas.catalog.projection.*;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * Entity resource definition.
+ */
+public class EntityResourceDefinition extends BaseResourceDefinition {
+ public EntityResourceDefinition() {
+ collectionProperties.add("name");
+ collectionProperties.add("id");
+ collectionProperties.add("type");
+
+ RelationProjection tagProjection = getTagProjection();
+ projections.put("tags", tagProjection);
+ RelationProjection traitProjection = getTraitProjection();
+ projections.put("traits", traitProjection);
+ projections.put("default", getDefaultRelationProjection());
+
+ relations.put(tagProjection.getName(), tagProjection.getRelation());
+ relations.put(traitProjection.getName(), traitProjection.getRelation());
+ }
+
+ @Override
+ public String getIdPropertyName() {
+ return "id";
+ }
+
+ // not meaningful for entities
+ @Override
+ public String getTypeName() {
+ return null;
+ }
+
+ @Override
+ public void validate(Request request) throws InvalidPayloadException {
+ // no op for entities as we don't currently create entities and
+ // each entity type is different
+ }
+
+ @Override
+ public String resolveHref(Map<String, Object> properties) {
+ Object id = properties.get("id");
+ return id == null ? null : String.format("v1/entities/%s", id);
+ }
+
+ private RelationProjection getTagProjection() {
+ Relation traitRelation = new TagRelation();
+ RelationProjection tagProjection = new RelationProjection("tags", Collections.singleton("name"),
+ traitRelation, Projection.Cardinality.MULTIPLE);
+ tagProjection.addPipe(new TransformFunctionPipe<>(
+ new PipeFunction<Collection<ProjectionResult>, Collection<ProjectionResult>>() {
+ @Override
+ public Collection<ProjectionResult> compute(Collection<ProjectionResult> results) {
+ for (ProjectionResult result : results) {
+ for (Map<String, Object> properties : result.getPropertyMaps()) {
+ properties.put("href", String.format("v1/entities/%s/tags/%s",
+ result.getStartingVertex().getProperty("id"), properties.get("name")));
+ }
+ }
+ return results;
+ }
+ }));
+ return tagProjection;
+ }
+
+ private RelationProjection getTraitProjection() {
+ return new RelationProjection("traits", Collections.<String>emptySet(),
+ new TraitRelation(), Projection.Cardinality.MULTIPLE);
+ }
+
+ private RelationProjection getDefaultRelationProjection() {
+ Relation genericRelation = new GenericRelation(this);
+ RelationProjection relationProjection = new RelationProjection(
+ "relations",
+ Arrays.asList("type", "id", "name"),
+ genericRelation, Projection.Cardinality.MULTIPLE);
+
+ relationProjection.addPipe(new TransformFunctionPipe<>(
+ new PipeFunction<Collection<ProjectionResult>, Collection<ProjectionResult>>() {
+ @Override
+ public Collection<ProjectionResult> compute(Collection<ProjectionResult> results) {
+ for (ProjectionResult result : results) {
+ for (Map<String, Object> properties : result.getPropertyMaps()) {
+ properties.put("href", String.format("v1/entities/%s", properties.get("id")));
+ }
+ }
+ return results;
+ }
+ }));
+ return relationProjection;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/definition/EntityTagResourceDefinition.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/definition/EntityTagResourceDefinition.java b/catalog/src/main/java/org/apache/atlas/catalog/definition/EntityTagResourceDefinition.java
new file mode 100644
index 0000000..c5a4213
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/definition/EntityTagResourceDefinition.java
@@ -0,0 +1,105 @@
+/**
+ * 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.definition;
+
+import com.tinkerpop.pipes.PipeFunction;
+import com.tinkerpop.pipes.transform.TransformFunctionPipe;
+import org.apache.atlas.catalog.DefaultPropertyMapper;
+import org.apache.atlas.catalog.PropertyMapper;
+import org.apache.atlas.catalog.ResourceComparator;
+import org.apache.atlas.catalog.VertexWrapper;
+import org.apache.atlas.catalog.projection.Projection;
+import org.apache.atlas.catalog.projection.ProjectionResult;
+import org.apache.atlas.repository.Constants;
+import org.apache.atlas.typesystem.types.DataTypes;
+import org.apache.atlas.typesystem.types.utils.TypesUtil;
+
+import java.util.*;
+
+/**
+ * Entity Tag resource definition.
+ */
+public class EntityTagResourceDefinition extends BaseResourceDefinition {
+ public static final String ENTITY_GUID_PROPERTY = "entity-guid";
+
+ public EntityTagResourceDefinition() {
+ registerProperty(TypesUtil.createRequiredAttrDef("name", DataTypes.STRING_TYPE));
+
+ instanceProperties.add("name");
+ instanceProperties.add("description");
+ instanceProperties.add("creation_time");
+
+ collectionProperties.add("name");
+ collectionProperties.add("description");
+
+ projections.put("terms", getTermProjection());
+ }
+
+ @Override
+ public String getIdPropertyName() {
+ return "name";
+ }
+
+ //not meaningful for entity tags
+ @Override
+ public String getTypeName() {
+ return null;
+ }
+
+ @Override
+ public String resolveHref(Map<String, Object> properties) {
+ return String.format("v1/entities/%s/tags/%s", properties.get(ENTITY_GUID_PROPERTY), properties.get("name"));
+ }
+
+ private Projection getTermProjection() {
+ return new Projection("term", Projection.Cardinality.SINGLE,
+ new TransformFunctionPipe<>(new PipeFunction<VertexWrapper, Collection<ProjectionResult>>() {
+ @Override
+ public Collection<ProjectionResult> compute(VertexWrapper start) {
+ Map<String, Object> map = new TreeMap<>(new ResourceComparator());
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("v1/taxonomies/");
+
+ String fullyQualifiedName = start.getVertex().getProperty(Constants.ENTITY_TYPE_PROPERTY_KEY);
+ String[] paths = fullyQualifiedName.split("\\.");
+ // first path segment is the taxonomy
+ sb.append(paths[0]);
+
+ for (int i = 1; i < paths.length; ++i) {
+ String path = paths[i];
+ if (path != null && !path.isEmpty()) {
+ sb.append("/terms/");
+ sb.append(path);
+ }
+ }
+
+ map.put("href", sb.toString());
+ return Collections.singleton(new ProjectionResult("term", start,
+ Collections.singleton(map)));
+ }
+ }));
+ }
+
+ @Override
+ protected PropertyMapper createPropertyMapper() {
+ return new DefaultPropertyMapper(Collections.singletonMap(Constants.ENTITY_TYPE_PROPERTY_KEY, "name"),
+ Collections.singletonMap("name", Constants.ENTITY_TYPE_PROPERTY_KEY));
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/definition/ResourceDefinition.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/definition/ResourceDefinition.java b/catalog/src/main/java/org/apache/atlas/catalog/definition/ResourceDefinition.java
new file mode 100644
index 0000000..f310c5a
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/definition/ResourceDefinition.java
@@ -0,0 +1,112 @@
+/**
+ * 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.definition;
+
+import org.apache.atlas.catalog.PropertyMapper;
+import org.apache.atlas.catalog.PropertyValueFormatter;
+import org.apache.atlas.catalog.Request;
+import org.apache.atlas.catalog.exception.InvalidPayloadException;
+import org.apache.atlas.catalog.projection.Projection;
+import org.apache.atlas.catalog.projection.Relation;
+import org.apache.atlas.typesystem.types.AttributeDefinition;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * Resource definition.
+ */
+public interface ResourceDefinition {
+ /**
+ * The type name of the resource.
+ *
+ * @return the resources type name
+ */
+ String getTypeName();
+ /**
+ * Validate a user request.
+ *
+ * @param request user request
+ *
+ * @throws InvalidPayloadException if the request payload is invalid in any way
+ */
+ void validate(Request request) throws InvalidPayloadException;
+
+ /**
+ * Get the name of the resources id property.
+ *
+ * @return the id property name
+ */
+ String getIdPropertyName();
+
+ /**
+ * Get the property definitions for the resource.
+ *
+ * @return resource property definitions
+ */
+ //todo: abstract usage of AttributeDefinition
+ Collection<AttributeDefinition> getPropertyDefinitions();
+
+ /**
+ * Filter out properties which shouldn't be returned in the result.
+ * The passed in map is directly modified as well as returned.
+ *
+ * @param request user request
+ * @param propertyMap property map to filter
+ *
+ * @return the filtered property map
+ */
+ Map<String, Object> filterProperties(Request request, Map<String, Object> propertyMap);
+
+ /**
+ * Generate an href for the resource from the provided resource property map.
+ *
+ * @param properties resource property map
+ *
+ * @return a URL to be used as an href property value for the resource
+ */
+ String resolveHref(Map<String, Object> properties);
+
+ /**
+ * Get map of resource projections.
+ *
+ * @return map of resource projections
+ */
+ Map<String, Projection> getProjections();
+
+ /**
+ * Get map of resource relations.
+ *
+ * @return map of resource relations
+ */
+ Map<String, Relation> getRelations();
+
+ /**
+ * Get the property mapper associated with the resource.
+ *
+ * @return associated property mapper
+ */
+ PropertyMapper getPropertyMapper();
+
+ /**
+ * Get the registered property value formatters.
+ * @return map of property name to property value formatter
+ */
+ Map<String, PropertyValueFormatter> getPropertyValueFormatters();
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/definition/TaxonomyResourceDefinition.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/definition/TaxonomyResourceDefinition.java b/catalog/src/main/java/org/apache/atlas/catalog/definition/TaxonomyResourceDefinition.java
new file mode 100644
index 0000000..a3fbdf1
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/definition/TaxonomyResourceDefinition.java
@@ -0,0 +1,89 @@
+/**
+ * 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.definition;
+
+import com.tinkerpop.pipes.PipeFunction;
+import com.tinkerpop.pipes.transform.TransformFunctionPipe;
+import org.apache.atlas.catalog.Request;
+import org.apache.atlas.catalog.VertexWrapper;
+import org.apache.atlas.catalog.exception.InvalidPayloadException;
+import org.apache.atlas.catalog.projection.Projection;
+import org.apache.atlas.catalog.projection.ProjectionResult;
+import org.apache.atlas.typesystem.types.DataTypes;
+import org.apache.atlas.typesystem.types.utils.TypesUtil;
+
+import java.util.*;
+
+/**
+ * Taxonomy resource definition.
+ */
+public class TaxonomyResourceDefinition extends BaseResourceDefinition {
+ public TaxonomyResourceDefinition() {
+ registerProperty(TypesUtil.createUniqueRequiredAttrDef("name", DataTypes.STRING_TYPE));
+ registerProperty(TypesUtil.createOptionalAttrDef("description", DataTypes.STRING_TYPE));
+
+ //todo: combine with above registrations
+ instanceProperties.add("name");
+ instanceProperties.add("description");
+ instanceProperties.add("creation_time");
+
+ collectionProperties.add("name");
+ collectionProperties.add("description");
+
+ projections.put("terms", getTermsProjection());
+ }
+
+ @Override
+ public void validate(Request request) throws InvalidPayloadException {
+ super.validate(request);
+ if (String.valueOf(request.getProperties().get("name")).contains(".")) {
+ throw new InvalidPayloadException("The \"name\" property may not contain the character '.'");
+ }
+ }
+
+ @Override
+ public String getTypeName() {
+ return "Taxonomy";
+ }
+
+ @Override
+ public String getIdPropertyName() {
+ return "name";
+ }
+
+ @Override
+ public String resolveHref(Map<String, Object> properties) {
+ return String.format("v1/taxonomies/%s", properties.get("name"));
+ }
+
+ private Projection getTermsProjection() {
+ final String termsProjectionName = "terms";
+ return new Projection(termsProjectionName, Projection.Cardinality.SINGLE,
+ new TransformFunctionPipe<>(new PipeFunction<VertexWrapper, Collection<ProjectionResult>>() {
+ private String baseHref = "v1/taxonomies/";
+ @Override
+ public Collection<ProjectionResult> compute(VertexWrapper v) {
+ Map<String, Object> map = new HashMap<>();
+ map.put("href", baseHref + v.getProperty("name") + "/terms");
+ return Collections.singleton(new ProjectionResult(termsProjectionName, v,
+ Collections.singleton(map)));
+ }
+ }));
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/definition/TermResourceDefinition.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/definition/TermResourceDefinition.java b/catalog/src/main/java/org/apache/atlas/catalog/definition/TermResourceDefinition.java
new file mode 100644
index 0000000..19dd049
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/definition/TermResourceDefinition.java
@@ -0,0 +1,158 @@
+/**
+ * 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.definition;
+
+import com.tinkerpop.pipes.PipeFunction;
+import com.tinkerpop.pipes.transform.TransformFunctionPipe;
+import org.apache.atlas.catalog.Request;
+import org.apache.atlas.catalog.ResourceComparator;
+import org.apache.atlas.catalog.TermPath;
+import org.apache.atlas.catalog.VertexWrapper;
+import org.apache.atlas.catalog.exception.InvalidPayloadException;
+import org.apache.atlas.catalog.projection.Projection;
+import org.apache.atlas.catalog.projection.ProjectionResult;
+import org.apache.atlas.repository.Constants;
+import org.apache.atlas.typesystem.types.*;
+import org.apache.atlas.typesystem.types.utils.TypesUtil;
+
+import java.util.*;
+
+/**
+ * Term resource definition.
+ */
+public class TermResourceDefinition extends BaseResourceDefinition {
+ public TermResourceDefinition() {
+ registerProperty(TypesUtil.createRequiredAttrDef("name", DataTypes.STRING_TYPE));
+ registerProperty(TypesUtil.createOptionalAttrDef("description", DataTypes.STRING_TYPE));
+ registerProperty(TypesUtil.createOptionalAttrDef("available_as_tag", DataTypes.BOOLEAN_TYPE));
+ registerProperty(TypesUtil.createOptionalAttrDef("acceptable_use", DataTypes.STRING_TYPE));
+
+ instanceProperties.add("name");
+ instanceProperties.add("description");
+ instanceProperties.add("creation_time");
+ instanceProperties.add("available_as_tag");
+ instanceProperties.add("acceptable_use");
+
+ collectionProperties.add("name");
+ collectionProperties.add("description");
+
+ projections.put("terms", getSubTermProjection());
+ projections.put("hierarchy", getHierarchyProjection());
+ }
+
+ @Override
+ public void validate(Request request) throws InvalidPayloadException {
+ super.validate(request);
+
+ String name = request.getProperty("name");
+ // name will be in the fully qualified form: taxonomyName.termName
+ if (! name.contains(".")) {
+ throw new InvalidPayloadException("Term name must be in the form 'taxonomyName.termName.subTermName'");
+ }
+
+ if (! request.getProperties().containsKey("available_as_tag")) {
+ request.getProperties().put("available_as_tag", true);
+ }
+ }
+
+ @Override
+ public String getTypeName() {
+ return "Term";
+ }
+
+ @Override
+ public String getIdPropertyName() {
+ return "name";
+ }
+
+ //todo
+ @Override
+ public String resolveHref(Map<String, Object> properties) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("v1/taxonomies/");
+
+ TermPath termPath = new TermPath(String.valueOf(properties.get("name")));
+ String[] paths = termPath.getPathSegments();
+ sb.append(termPath.getTaxonomyName());
+
+ for (String path : paths) {
+ //todo: shouldn't need to check for null or empty after TermPath addition
+ if (path != null && !path.isEmpty()) {
+ sb.append("/terms/");
+ sb.append(path);
+ }
+ }
+
+ return sb.toString();
+ }
+
+ private Projection getHierarchyProjection() {
+ final String projectionName = "hierarchy";
+ return new Projection(projectionName, Projection.Cardinality.SINGLE,
+ new TransformFunctionPipe<>(new PipeFunction<VertexWrapper, Collection<ProjectionResult>>() {
+ @Override
+ public Collection<ProjectionResult> compute(VertexWrapper start) {
+ Map<String, Object> map = new TreeMap<>(new ResourceComparator());
+
+ TermPath termPath = new TermPath(start.getVertex().<String>getProperty(
+ Constants.ENTITY_TYPE_PROPERTY_KEY));
+
+ map.put("path", termPath.getPath());
+ map.put("short_name", termPath.getShortName());
+ map.put("taxonomy", termPath.getTaxonomyName());
+
+ return Collections.singleton(new ProjectionResult(projectionName, start,
+ Collections.singleton(map)));
+ }
+ }));
+
+ }
+
+ private Projection getSubTermProjection() {
+ //todo: combine with other term projections
+ final String termsProjectionName = "terms";
+ return new Projection(termsProjectionName, Projection.Cardinality.SINGLE,
+ new TransformFunctionPipe<>(new PipeFunction<VertexWrapper, Collection<ProjectionResult>>() {
+ @Override
+ public Collection<ProjectionResult> compute(VertexWrapper start) {
+ Map<String, Object> map = new TreeMap<>(new ResourceComparator());
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("v1/taxonomies/");
+
+ TermPath termPath = new TermPath(start.getVertex().<String>getProperty(Constants.ENTITY_TYPE_PROPERTY_KEY));
+ String[] paths = termPath.getPathSegments();
+ sb.append(termPath.getTaxonomyName());
+
+ for (String path : paths) {
+ //todo: shouldn't need to check for null or empty after TermPath addition
+ if (path != null && !path.isEmpty()) {
+ sb.append("/terms/");
+ sb.append(path);
+ }
+ }
+ sb.append("/terms");
+
+ map.put("href", sb.toString());
+ return Collections.singleton(new ProjectionResult(termsProjectionName, start,
+ Collections.singleton(map)));
+ }
+ }));
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/exception/CatalogException.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/exception/CatalogException.java b/catalog/src/main/java/org/apache/atlas/catalog/exception/CatalogException.java
new file mode 100644
index 0000000..7bb2f7b
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/exception/CatalogException.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.exception;
+
+/**
+ * Base checked catalog exception.
+ */
+public class CatalogException extends Exception {
+
+ private int status;
+
+ public CatalogException(String message, int status) {
+ super(message);
+ this.status = status;
+ }
+
+ public int getStatus() {
+ return status;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/exception/CatalogRuntimeException.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/exception/CatalogRuntimeException.java b/catalog/src/main/java/org/apache/atlas/catalog/exception/CatalogRuntimeException.java
new file mode 100644
index 0000000..51fd7af
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/exception/CatalogRuntimeException.java
@@ -0,0 +1,43 @@
+/**
+ * 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.exception;
+
+/**
+ * Base runtime catalog exception.
+ */
+public class CatalogRuntimeException extends RuntimeException {
+ int statusCode = 500;
+
+ public CatalogRuntimeException(Exception e) {
+ super("", e);
+ }
+
+ public CatalogRuntimeException(String message, Exception e) {
+ super(message, e);
+ }
+
+ public CatalogRuntimeException(String message, int statusCode) {
+ super(message);
+ this.statusCode = statusCode;
+ }
+
+ public int getStatusCode() {
+ return statusCode;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/exception/InvalidPayloadException.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/exception/InvalidPayloadException.java b/catalog/src/main/java/org/apache/atlas/catalog/exception/InvalidPayloadException.java
new file mode 100644
index 0000000..34c5ab5
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/exception/InvalidPayloadException.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.exception;
+
+import java.util.Collection;
+
+/**
+ * Exception used for invalid API payloads.
+ */
+public class InvalidPayloadException extends CatalogException {
+ private final static String baseMsg = "Invalid Request.";
+ private final static String missingMsg = " The following required properties are missing: %s.";
+ private final static String unknownMsg = " The following properties are not supported: %s";
+
+ public InvalidPayloadException(Collection<String> missingProperties, Collection<String> unknownProperties) {
+ super(baseMsg + (!missingProperties.isEmpty() ? String.format(missingMsg, missingProperties): "") +
+ (!unknownProperties.isEmpty() ? String.format(unknownMsg, unknownProperties): ""), 400);
+ }
+
+ public InvalidPayloadException(String msg) {
+ super(msg, 400);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/exception/InvalidQueryException.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/exception/InvalidQueryException.java b/catalog/src/main/java/org/apache/atlas/catalog/exception/InvalidQueryException.java
new file mode 100644
index 0000000..a7abe23
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/exception/InvalidQueryException.java
@@ -0,0 +1,28 @@
+/**
+ * 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.exception;
+
+/**
+ * Exception for invalid user query.
+ */
+public class InvalidQueryException extends CatalogException {
+ public InvalidQueryException(String message) {
+ super("Unable to parse query: " + message, 400);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/exception/ResourceAlreadyExistsException.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/exception/ResourceAlreadyExistsException.java b/catalog/src/main/java/org/apache/atlas/catalog/exception/ResourceAlreadyExistsException.java
new file mode 100644
index 0000000..d7670c1
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/exception/ResourceAlreadyExistsException.java
@@ -0,0 +1,28 @@
+/**
+ * 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.exception;
+
+/**
+ * Exception used when an attempt is made to create a resource which already exists.
+ */
+public class ResourceAlreadyExistsException extends CatalogException {
+ public ResourceAlreadyExistsException(String message) {
+ super(message, 409);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/exception/ResourceNotFoundException.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/exception/ResourceNotFoundException.java b/catalog/src/main/java/org/apache/atlas/catalog/exception/ResourceNotFoundException.java
new file mode 100644
index 0000000..0307137
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/exception/ResourceNotFoundException.java
@@ -0,0 +1,28 @@
+/**
+ * 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.exception;
+
+/**
+ * Exception used when an explicitly requested resource doesn't exist.
+ */
+public class ResourceNotFoundException extends CatalogException {
+ public ResourceNotFoundException(String message) {
+ super(message, 404);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/projection/GenericRelation.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/projection/GenericRelation.java b/catalog/src/main/java/org/apache/atlas/catalog/projection/GenericRelation.java
new file mode 100644
index 0000000..5f59bea
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/projection/GenericRelation.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.projection;
+
+import com.tinkerpop.blueprints.Direction;
+import com.tinkerpop.blueprints.Edge;
+import com.tinkerpop.blueprints.Vertex;
+import com.tinkerpop.pipes.Pipe;
+import org.apache.atlas.catalog.VertexWrapper;
+import org.apache.atlas.catalog.definition.ResourceDefinition;
+import org.apache.atlas.repository.Constants;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Represents a generic relation
+ */
+public class GenericRelation implements Relation {
+ private final ResourceDefinition resourceDefinition;
+
+ public GenericRelation(ResourceDefinition resourceDefinition) {
+ this.resourceDefinition = resourceDefinition;
+ }
+
+ @Override
+ public Collection<RelationSet> traverse(VertexWrapper vWrapper) {
+ Collection<RelationSet> relations = new ArrayList<>();
+ Vertex v = vWrapper.getVertex();
+ String vertexType = v.getProperty(Constants.ENTITY_TYPE_PROPERTY_KEY);
+ Map<String, Collection<VertexWrapper>> vertexMap = new HashMap<>();
+ for (Edge e : v.getEdges(Direction.OUT)) {
+ String edgeLabel = e.getLabel();
+ String edgePrefix = String.format("%s%s.", Constants.INTERNAL_PROPERTY_KEY_PREFIX, vertexType);
+ if (edgeLabel.startsWith(edgePrefix)) {
+ Vertex adjacentVertex = e.getVertex(Direction.IN);
+ VertexWrapper relationVertex = new VertexWrapper(adjacentVertex, resourceDefinition);
+ String relationName = edgeLabel.substring(edgePrefix.length());
+ Collection<VertexWrapper> vertices = vertexMap.get(relationName);
+ if (vertices == null) {
+ vertices = new ArrayList<>();
+ vertexMap.put(relationName, vertices);
+ }
+ vertices.add(relationVertex);
+ }
+ }
+ for (Map.Entry<String, Collection<VertexWrapper>> entry : vertexMap.entrySet()) {
+ relations.add(new RelationSet(entry.getKey(), entry.getValue()));
+ }
+ return relations;
+ }
+
+ @Override
+ public Pipe asPipe() {
+ return null;
+ }
+
+ @Override
+ public ResourceDefinition getResourceDefinition() {
+ return resourceDefinition;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/projection/Projection.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/projection/Projection.java b/catalog/src/main/java/org/apache/atlas/catalog/projection/Projection.java
new file mode 100644
index 0000000..daa1351
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/projection/Projection.java
@@ -0,0 +1,66 @@
+/**
+ * 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.projection;
+
+import com.tinkerpop.pipes.Pipe;
+import com.tinkerpop.pipes.util.Pipeline;
+import org.apache.atlas.catalog.VertexWrapper;
+
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * Projection representation.
+ * Used to project properties onto a resource from another source.
+ */
+public class Projection {
+ public enum Cardinality {SINGLE, MULTIPLE}
+
+ private final String m_name;
+ private final Cardinality m_cardinality;
+ protected Pipeline<VertexWrapper, Collection<ProjectionResult>> m_pipeline = new Pipeline<>();
+
+ public Projection(String name, Cardinality cardinality) {
+ m_name = name;
+ m_cardinality = cardinality;
+ }
+
+ public Projection(String name, Cardinality cardinality, Pipe<VertexWrapper, Collection<ProjectionResult>> pipe) {
+ m_name = name;
+ m_cardinality = cardinality;
+ m_pipeline.addPipe(pipe);
+ }
+
+ public Collection<ProjectionResult> values(VertexWrapper start) {
+ m_pipeline.setStarts(Collections.singleton(start));
+ return m_pipeline.iterator().next();
+ }
+
+ public void addPipe(Pipe<Collection<ProjectionResult>, Collection<ProjectionResult>> p) {
+ m_pipeline.addPipe(p);
+ }
+
+ public String getName() {
+ return m_name;
+ }
+
+ public Cardinality getCardinality() {
+ return m_cardinality;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/projection/ProjectionResult.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/projection/ProjectionResult.java b/catalog/src/main/java/org/apache/atlas/catalog/projection/ProjectionResult.java
new file mode 100644
index 0000000..7b12e2d
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/projection/ProjectionResult.java
@@ -0,0 +1,51 @@
+/**
+ * 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.projection;
+
+import org.apache.atlas.catalog.VertexWrapper;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * Result of a projection.
+ */
+public class ProjectionResult {
+ private final VertexWrapper m_startVertex;
+ private final String m_name;
+ private final Collection<Map<String, Object>> m_propertyMaps;
+
+ public ProjectionResult(String name, VertexWrapper startingVertex, Collection<Map<String, Object>> propertyMaps) {
+ m_name = name;
+ m_startVertex = startingVertex;
+ m_propertyMaps = propertyMaps;
+ }
+
+ public String getName() {
+ return m_name;
+ }
+
+ public VertexWrapper getStartingVertex() {
+ return m_startVertex;
+ }
+
+ public Collection<Map<String, Object>> getPropertyMaps() {
+ return m_propertyMaps;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/projection/Relation.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/projection/Relation.java b/catalog/src/main/java/org/apache/atlas/catalog/projection/Relation.java
new file mode 100644
index 0000000..b19bc15
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/projection/Relation.java
@@ -0,0 +1,53 @@
+/**
+ * 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.projection;
+
+import com.tinkerpop.pipes.Pipe;
+import org.apache.atlas.catalog.VertexWrapper;
+import org.apache.atlas.catalog.definition.ResourceDefinition;
+
+import java.util.Collection;
+
+/**
+ * Represents the relationship from one vertex to another via an edge.
+ */
+public interface Relation {
+ /**
+ * Traverse the relation.
+ *
+ * @param vWrapper vertex to start traversal from
+ *
+ * @return results of the traversal
+ */
+ Collection<RelationSet> traverse(VertexWrapper vWrapper);
+
+ /**
+ * Get the pipe representation of the traversal.
+ *
+ * @return pipe representation
+ */
+ Pipe asPipe();
+
+ /**
+ * Get the associated resource definition.
+ *
+ * @return associated resource definition
+ */
+ ResourceDefinition getResourceDefinition();
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/projection/RelationProjection.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/projection/RelationProjection.java b/catalog/src/main/java/org/apache/atlas/catalog/projection/RelationProjection.java
new file mode 100644
index 0000000..e435628
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/projection/RelationProjection.java
@@ -0,0 +1,69 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * <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.projection;
+
+import com.tinkerpop.pipes.PipeFunction;
+import com.tinkerpop.pipes.transform.TransformFunctionPipe;
+import org.apache.atlas.catalog.ResourceComparator;
+import org.apache.atlas.catalog.VertexWrapper;
+
+import java.util.*;
+
+/**
+ * Projection based on a relation.
+ */
+public class RelationProjection extends Projection {
+
+ private Relation relation;
+ public RelationProjection(String name, final Collection<String> fields, final Relation relation, Cardinality cardinality) {
+ super(name, cardinality, new TransformFunctionPipe<>(
+ new PipeFunction<VertexWrapper, Collection<ProjectionResult>>() {
+ @Override
+ public Collection<ProjectionResult> compute(VertexWrapper start) {
+ Collection<ProjectionResult> projectionResults = new ArrayList<>();
+
+ for (RelationSet relationSet : relation.traverse(start)) {
+ Collection<Map<String, Object>> propertyMaps = new ArrayList<>();
+
+ for (VertexWrapper vWrapper : relationSet.getVertices()) {
+ Map<String, Object> propertyMap = new TreeMap<>(new ResourceComparator());
+ propertyMaps.add(propertyMap);
+
+ if (fields.isEmpty()) {
+ for (String property : vWrapper.getPropertyKeys()) {
+ propertyMap.put(property, vWrapper.<String>getProperty(property));
+ }
+ } else {
+ for (String property : fields) {
+ propertyMap.put(property, vWrapper.<String>getProperty(property));
+ }
+ }
+ }
+ projectionResults.add(new ProjectionResult(relationSet.getName(), start, propertyMaps));
+ }
+ return projectionResults;
+ }
+ }));
+ this.relation = relation;
+ }
+
+ public Relation getRelation() {
+ return relation;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/projection/RelationSet.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/projection/RelationSet.java b/catalog/src/main/java/org/apache/atlas/catalog/projection/RelationSet.java
new file mode 100644
index 0000000..4adf861
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/projection/RelationSet.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.projection;
+
+import org.apache.atlas.catalog.VertexWrapper;
+
+import java.util.*;
+
+/**
+ * Encapsulates the response of a relation traversal.
+ */
+public class RelationSet {
+
+ private final String m_name;
+ private final Collection<VertexWrapper> m_vertices;
+
+ public RelationSet(String name, Collection<VertexWrapper> vertices) {
+ m_name = name;
+ m_vertices = vertices;
+ }
+
+ public String getName() {
+ return m_name;
+ }
+
+ public Collection<VertexWrapper> getVertices() {
+ return Collections.unmodifiableCollection(m_vertices);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/projection/TagRelation.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/projection/TagRelation.java b/catalog/src/main/java/org/apache/atlas/catalog/projection/TagRelation.java
new file mode 100644
index 0000000..a5e15c6
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/projection/TagRelation.java
@@ -0,0 +1,73 @@
+/**
+ * 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.projection;
+
+import com.tinkerpop.blueprints.Direction;
+import com.tinkerpop.blueprints.Edge;
+import com.tinkerpop.blueprints.Vertex;
+import com.tinkerpop.pipes.Pipe;
+import com.tinkerpop.pipes.PipeFunction;
+import com.tinkerpop.pipes.filter.FilterFunctionPipe;
+import org.apache.atlas.catalog.TermVertexWrapper;
+import org.apache.atlas.catalog.VertexWrapper;
+import org.apache.atlas.catalog.definition.EntityTagResourceDefinition;
+import org.apache.atlas.catalog.definition.ResourceDefinition;
+import org.apache.atlas.repository.Constants;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * Relation for adjacent Tag vertices.
+ */
+public class TagRelation implements Relation {
+ private static ResourceDefinition resourceDefinition = new EntityTagResourceDefinition();
+ @Override
+ public Collection<RelationSet> traverse(VertexWrapper vWrapper) {
+ Vertex v = vWrapper.getVertex();
+ Collection<VertexWrapper> vertices = new ArrayList<>();
+ for (Edge e : v.getEdges(Direction.OUT)) {
+ if (e.getLabel().startsWith(v.<String>getProperty(Constants.ENTITY_TYPE_PROPERTY_KEY))) {
+ VertexWrapper trait = new TermVertexWrapper(e.getVertex(Direction.IN));
+ if (trait.getPropertyKeys().contains("available_as_tag")) {
+ vertices.add(trait);
+ }
+ }
+ }
+ return Collections.singletonList(new RelationSet("tags", vertices));
+ }
+
+ @Override
+ public Pipe asPipe() {
+ return new FilterFunctionPipe<>(new PipeFunction<Edge, Boolean>() {
+ @Override
+ public Boolean compute(Edge edge) {
+ String name = edge.getVertex(Direction.OUT).getProperty(Constants.ENTITY_TYPE_PROPERTY_KEY);
+ VertexWrapper v = new TermVertexWrapper(edge.getVertex(Direction.IN));
+ return edge.getLabel().startsWith(name) && v.getPropertyKeys().contains("available_as_tag");
+ }
+ });
+ }
+
+ @Override
+ public ResourceDefinition getResourceDefinition() {
+ return resourceDefinition;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/projection/TraitRelation.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/projection/TraitRelation.java b/catalog/src/main/java/org/apache/atlas/catalog/projection/TraitRelation.java
new file mode 100644
index 0000000..5f11474
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/projection/TraitRelation.java
@@ -0,0 +1,76 @@
+/**
+ * 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.projection;
+
+import com.tinkerpop.blueprints.Direction;
+import com.tinkerpop.blueprints.Edge;
+import com.tinkerpop.blueprints.Vertex;
+import com.tinkerpop.pipes.Pipe;
+import com.tinkerpop.pipes.PipeFunction;
+import com.tinkerpop.pipes.filter.FilterFunctionPipe;
+import org.apache.atlas.catalog.TermVertexWrapper;
+import org.apache.atlas.catalog.VertexWrapper;
+import org.apache.atlas.catalog.definition.EntityTagResourceDefinition;
+import org.apache.atlas.catalog.definition.ResourceDefinition;
+import org.apache.atlas.repository.Constants;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * Trait specific relation.
+ */
+//todo: combine with TagRelation
+public class TraitRelation implements Relation {
+ //todo: for now using entity tag resource definition
+ private static ResourceDefinition resourceDefinition = new EntityTagResourceDefinition();
+
+ @Override
+ public Collection<RelationSet> traverse(VertexWrapper vWrapper) {
+ Vertex v = vWrapper.getVertex();
+ Collection<VertexWrapper> vertices = new ArrayList<>();
+ for (Edge e : v.getEdges(Direction.OUT)) {
+ if (e.getLabel().startsWith(v.<String>getProperty(Constants.ENTITY_TYPE_PROPERTY_KEY))) {
+ VertexWrapper trait = new TermVertexWrapper(e.getVertex(Direction.IN));
+ if (! trait.getPropertyKeys().contains("available_as_tag")) {
+ vertices.add(trait);
+ }
+ }
+ }
+ return Collections.singletonList(new RelationSet("traits", vertices));
+ }
+
+ @Override
+ public Pipe asPipe() {
+ return new FilterFunctionPipe<>(new PipeFunction<Edge, Boolean>() {
+ @Override
+ public Boolean compute(Edge edge) {
+ String type = edge.getVertex(Direction.OUT).getProperty(Constants.ENTITY_TYPE_PROPERTY_KEY);
+ VertexWrapper v = new TermVertexWrapper(edge.getVertex(Direction.IN));
+ return edge.getLabel().startsWith(type) && ! v.getPropertyKeys().contains("available_as_tag");
+ }
+ });
+ }
+
+ @Override
+ public ResourceDefinition getResourceDefinition() {
+ return resourceDefinition;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/query/AlwaysQueryExpression.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/query/AlwaysQueryExpression.java b/catalog/src/main/java/org/apache/atlas/catalog/query/AlwaysQueryExpression.java
new file mode 100644
index 0000000..d120bc4
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/query/AlwaysQueryExpression.java
@@ -0,0 +1,46 @@
+/**
+ * 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.query;
+
+import com.tinkerpop.pipes.Pipe;
+import org.apache.atlas.catalog.VertexWrapper;
+
+/**
+ * Query expression which always returns true.
+ */
+public class AlwaysQueryExpression extends BaseQueryExpression {
+ protected AlwaysQueryExpression() {
+ super(null, null, null);
+ }
+
+ @Override
+ public Pipe asPipe() {
+ return null;
+ }
+
+ @Override
+ public boolean evaluate(VertexWrapper vWrapper) {
+ return ! negate;
+ }
+
+ @Override
+ public boolean evaluate(Object value) {
+ return true;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/query/AtlasEntityQuery.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/query/AtlasEntityQuery.java b/catalog/src/main/java/org/apache/atlas/catalog/query/AtlasEntityQuery.java
new file mode 100644
index 0000000..e2bc597
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/query/AtlasEntityQuery.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.query;
+
+import com.tinkerpop.gremlin.java.GremlinPipeline;
+import org.apache.atlas.catalog.Request;
+import org.apache.atlas.catalog.definition.ResourceDefinition;
+import org.apache.atlas.repository.Constants;
+
+/**
+ * Entity resource query.
+ */
+public class AtlasEntityQuery extends BaseQuery {
+ public AtlasEntityQuery(QueryExpression queryExpression, ResourceDefinition resourceDefinition, Request request) {
+ super(queryExpression, resourceDefinition, request);
+ }
+
+ protected GremlinPipeline getInitialPipeline() {
+ //todo: the property 'entityText' isn't currently indexed
+ //todo: we could use Constants.ENTITY_TYPE_PROPERTY_KEY initially but trait instances also contain this property
+ return new GremlinPipeline(getGraph()).V().has(Constants.ENTITY_TEXT_PROPERTY_KEY).
+ hasNot(Constants.ENTITY_TYPE_PROPERTY_KEY, "Taxonomy");
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/query/AtlasEntityTagQuery.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/query/AtlasEntityTagQuery.java b/catalog/src/main/java/org/apache/atlas/catalog/query/AtlasEntityTagQuery.java
new file mode 100644
index 0000000..013bb8a
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/query/AtlasEntityTagQuery.java
@@ -0,0 +1,73 @@
+/**
+ * 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.query;
+
+import com.tinkerpop.blueprints.Direction;
+import com.tinkerpop.blueprints.Edge;
+import com.tinkerpop.gremlin.java.GremlinPipeline;
+import com.tinkerpop.pipes.PipeFunction;
+import com.tinkerpop.pipes.filter.FilterFunctionPipe;
+import org.apache.atlas.catalog.Request;
+import org.apache.atlas.catalog.TermVertexWrapper;
+import org.apache.atlas.catalog.VertexWrapper;
+import org.apache.atlas.catalog.definition.EntityTagResourceDefinition;
+import org.apache.atlas.catalog.definition.ResourceDefinition;
+import org.apache.atlas.repository.Constants;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Entity Tag resource query.
+ */
+public class AtlasEntityTagQuery extends BaseQuery {
+ private final String guid;
+
+ public AtlasEntityTagQuery(QueryExpression queryExpression, ResourceDefinition resourceDefinition, String guid, Request request) {
+ super(queryExpression, resourceDefinition, request);
+ this.guid = guid;
+ }
+
+ @Override
+ protected GremlinPipeline getInitialPipeline() {
+ GremlinPipeline p = new GremlinPipeline(getGraph()).V().has(Constants.GUID_PROPERTY_KEY, guid).outE();
+ //todo: this is basically the same pipeline used in TagRelation.asPipe()
+ p.add(new FilterFunctionPipe<>(new PipeFunction<Edge, Boolean>() {
+ @Override
+ public Boolean compute(Edge edge) {
+ String type = edge.getVertex(Direction.OUT).getProperty(Constants.ENTITY_TYPE_PROPERTY_KEY);
+ VertexWrapper v = new TermVertexWrapper(edge.getVertex(Direction.IN));
+ return edge.getLabel().startsWith(type) && v.getPropertyKeys().contains("available_as_tag");
+ }
+ }));
+
+ return p.inV();
+ }
+
+ //todo: duplication of effort with resource definition
+ @Override
+ protected void addHref(Map<String, Object> propertyMap) {
+ Map<String, Object> map = new HashMap<>(propertyMap);
+ map.put(EntityTagResourceDefinition.ENTITY_GUID_PROPERTY, guid);
+ String href = resourceDefinition.resolveHref(map);
+ if (href != null) {
+ propertyMap.put("href", href);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/query/AtlasQuery.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/query/AtlasQuery.java b/catalog/src/main/java/org/apache/atlas/catalog/query/AtlasQuery.java
new file mode 100644
index 0000000..af14697
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/query/AtlasQuery.java
@@ -0,0 +1,37 @@
+/**
+ * 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.query;
+
+import org.apache.atlas.catalog.exception.ResourceNotFoundException;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * Query functionality.
+ */
+public interface AtlasQuery {
+ /**
+ * Execute the query.
+ *
+ * @return collection of property maps, one per matching resource
+ * @throws ResourceNotFoundException if an explicitly specified resource doesn't exist
+ */
+ Collection<Map<String, Object>> execute() throws ResourceNotFoundException;
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/query/AtlasTaxonomyQuery.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/query/AtlasTaxonomyQuery.java b/catalog/src/main/java/org/apache/atlas/catalog/query/AtlasTaxonomyQuery.java
new file mode 100644
index 0000000..787f734
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/query/AtlasTaxonomyQuery.java
@@ -0,0 +1,37 @@
+/**
+ * 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.query;
+
+import com.tinkerpop.gremlin.java.GremlinPipeline;
+import org.apache.atlas.catalog.Request;
+import org.apache.atlas.catalog.definition.ResourceDefinition;
+
+/**
+ * Taxonomy resource query.
+ */
+public class AtlasTaxonomyQuery extends BaseQuery {
+ public AtlasTaxonomyQuery(QueryExpression queryExpression, ResourceDefinition resourceDefinition, Request request) {
+ super(queryExpression, resourceDefinition, request);
+ }
+
+ @Override
+ protected GremlinPipeline getInitialPipeline() {
+ return new GremlinPipeline(getGraph()).V().has("__typeName", "Taxonomy");
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/query/AtlasTermQuery.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/query/AtlasTermQuery.java b/catalog/src/main/java/org/apache/atlas/catalog/query/AtlasTermQuery.java
new file mode 100644
index 0000000..0065101
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/query/AtlasTermQuery.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
+ * <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.query;
+
+import com.thinkaurelius.titan.core.attribute.Text;
+import com.tinkerpop.gremlin.java.GremlinPipeline;
+import org.apache.atlas.catalog.Request;
+import org.apache.atlas.catalog.TermPath;
+import org.apache.atlas.catalog.definition.ResourceDefinition;
+import org.apache.atlas.repository.Constants;
+
+/**
+ * Term resource query.
+ */
+public class AtlasTermQuery extends BaseQuery {
+ private final TermPath termPath;
+
+ public AtlasTermQuery(QueryExpression queryExpression, ResourceDefinition resourceDefinition, TermPath termPath, Request request) {
+ super(queryExpression, resourceDefinition, request);
+ this.termPath = termPath;
+ }
+
+ @Override
+ protected GremlinPipeline getInitialPipeline() {
+ return new GremlinPipeline(getGraph()).V().has("Taxonomy.name", termPath.getTaxonomyName()).out().
+ has(Constants.ENTITY_TYPE_PROPERTY_KEY, Text.PREFIX, termPath.getFullyQualifiedName());
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/query/BaseQuery.java
----------------------------------------------------------------------
diff --git a/catalog/src/main/java/org/apache/atlas/catalog/query/BaseQuery.java b/catalog/src/main/java/org/apache/atlas/catalog/query/BaseQuery.java
new file mode 100644
index 0000000..ac8ca6b
--- /dev/null
+++ b/catalog/src/main/java/org/apache/atlas/catalog/query/BaseQuery.java
@@ -0,0 +1,121 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * <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.query;
+
+import com.thinkaurelius.titan.core.TitanGraph;
+import com.tinkerpop.blueprints.Vertex;
+import com.tinkerpop.gremlin.java.GremlinPipeline;
+import com.tinkerpop.pipes.Pipe;
+import org.apache.atlas.catalog.Request;
+import org.apache.atlas.catalog.VertexWrapper;
+import org.apache.atlas.catalog.definition.ResourceDefinition;
+import org.apache.atlas.catalog.exception.ResourceNotFoundException;
+import org.apache.atlas.catalog.projection.Projection;
+import org.apache.atlas.catalog.projection.ProjectionResult;
+import org.apache.atlas.repository.graph.TitanGraphProvider;
+
+import java.util.*;
+
+/**
+ * Base Query implementation.
+ */
+public abstract class BaseQuery implements AtlasQuery {
+ protected final QueryExpression queryExpression;
+ protected final ResourceDefinition resourceDefinition;
+ protected final Request request;
+
+ public BaseQuery(QueryExpression queryExpression, ResourceDefinition resourceDefinition, Request request) {
+ this.queryExpression = queryExpression;
+ this.resourceDefinition = resourceDefinition;
+ this.request = request;
+ }
+
+ public Collection<Map<String, Object>> execute() throws ResourceNotFoundException {
+ Collection<Map<String, Object>> resultMaps = new ArrayList<>();
+
+ for (Vertex vertex : executeQuery()) {
+ resultMaps.add(processPropertyMap(new VertexWrapper(vertex, resourceDefinition)));
+ }
+ return resultMaps;
+ }
+
+ private List<Vertex> executeQuery() {
+ GremlinPipeline pipeline = getInitialPipeline().as("root");
+
+ Pipe adapterPipe = queryExpression.asPipe();
+ //todo: AlwaysQueryAdapter returns null for pipe
+ //todo: Is there a no-op pipe that I could add that wouldn't negatively affect performance
+ return adapterPipe == null ?
+ pipeline.toList() :
+ pipeline.add(adapterPipe).back("root").toList();
+ }
+
+ protected abstract GremlinPipeline getInitialPipeline();
+
+ // todo: consider getting
+ protected Map<String, Object> processPropertyMap(VertexWrapper vertex) {
+ Map<String, Object> propertyMap = vertex.getPropertyMap();
+ resourceDefinition.filterProperties(request, propertyMap);
+ addHref(propertyMap);
+
+ return request.getCardinality() == Request.Cardinality.INSTANCE ?
+ applyProjections(vertex, propertyMap) :
+ propertyMap;
+ }
+
+ protected void addHref(Map<String, Object> propertyMap) {
+ String href = resourceDefinition.resolveHref(propertyMap);
+ if (href != null) {
+ propertyMap.put("href", href);
+ }
+ }
+
+ private Map<String, Object> applyProjections(VertexWrapper vertex, Map<String, Object> propertyMap) {
+ for (Projection p : resourceDefinition.getProjections().values()) {
+ for (ProjectionResult projectionResult : p.values(vertex)) {
+ if (p.getCardinality() == Projection.Cardinality.MULTIPLE) {
+ propertyMap.put(projectionResult.getName(), projectionResult.getPropertyMaps());
+ } else {
+ for (Map<String, Object> projectionMap : projectionResult.getPropertyMaps()) {
+ propertyMap.put(projectionResult.getName(), projectionMap);
+ }
+ }
+ }
+ }
+ return propertyMap;
+ }
+
+ protected QueryExpression getQueryExpression() {
+ return queryExpression;
+ }
+
+ protected ResourceDefinition getResourceDefinition() {
+ return resourceDefinition;
+ }
+
+ protected Request getRequest() {
+ return request;
+ }
+
+ //todo: abstract
+ // Underlying method is synchronized and caches the graph in a static field
+ protected TitanGraph getGraph() {
+ return TitanGraphProvider.getGraphInstance();
+ }
+}