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(); + } +}
