ATLAS-491 Business Catalog / Taxonomy (jspeidel via yhemanth)
Project: http://git-wip-us.apache.org/repos/asf/incubator-atlas/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-atlas/commit/aaf2971a Tree: http://git-wip-us.apache.org/repos/asf/incubator-atlas/tree/aaf2971a Diff: http://git-wip-us.apache.org/repos/asf/incubator-atlas/diff/aaf2971a Branch: refs/heads/master Commit: aaf2971ad16ccd9c37040f593121695cd8c9cacb Parents: b65dd91 Author: Hemanth Yamijala <[email protected]> Authored: Wed May 18 18:33:39 2016 +0530 Committer: Hemanth Yamijala <[email protected]> Committed: Wed May 18 18:33:39 2016 +0530 ---------------------------------------------------------------------- catalog/pom.xml | 122 +++++ .../apache/atlas/catalog/AtlasTypeSystem.java | 79 ++++ .../org/apache/atlas/catalog/BaseRequest.java | 62 +++ .../atlas/catalog/BaseResourceProvider.java | 40 ++ .../apache/atlas/catalog/CollectionRequest.java | 35 ++ .../atlas/catalog/DefaultDateFormatter.java | 39 ++ .../atlas/catalog/DefaultPropertyMapper.java | 142 ++++++ .../apache/atlas/catalog/DefaultTypeSystem.java | 130 ++++++ .../atlas/catalog/EntityResourceProvider.java | 72 +++ .../catalog/EntityTagResourceProvider.java | 135 ++++++ .../apache/atlas/catalog/InstanceRequest.java | 35 ++ .../apache/atlas/catalog/JsonSerializer.java | 90 ++++ .../apache/atlas/catalog/PropertyMapper.java | 45 ++ .../atlas/catalog/PropertyValueFormatter.java | 33 ++ .../java/org/apache/atlas/catalog/Request.java | 77 ++++ .../atlas/catalog/ResourceComparator.java | 62 +++ .../apache/atlas/catalog/ResourceProvider.java | 75 ++++ .../java/org/apache/atlas/catalog/Result.java | 50 +++ .../atlas/catalog/TaxonomyResourceProvider.java | 80 ++++ .../java/org/apache/atlas/catalog/TermPath.java | 111 +++++ .../atlas/catalog/TermResourceProvider.java | 128 ++++++ .../apache/atlas/catalog/TermVertexWrapper.java | 36 ++ .../org/apache/atlas/catalog/VertexWrapper.java | 111 +++++ .../definition/BaseResourceDefinition.java | 150 +++++++ .../definition/EntityResourceDefinition.java | 120 +++++ .../definition/EntityTagResourceDefinition.java | 105 +++++ .../catalog/definition/ResourceDefinition.java | 112 +++++ .../definition/TaxonomyResourceDefinition.java | 89 ++++ .../definition/TermResourceDefinition.java | 158 +++++++ .../catalog/exception/CatalogException.java | 36 ++ .../exception/CatalogRuntimeException.java | 43 ++ .../exception/InvalidPayloadException.java | 39 ++ .../exception/InvalidQueryException.java | 28 ++ .../ResourceAlreadyExistsException.java | 28 ++ .../exception/ResourceNotFoundException.java | 28 ++ .../catalog/projection/GenericRelation.java | 80 ++++ .../atlas/catalog/projection/Projection.java | 66 +++ .../catalog/projection/ProjectionResult.java | 51 +++ .../atlas/catalog/projection/Relation.java | 53 +++ .../catalog/projection/RelationProjection.java | 69 +++ .../atlas/catalog/projection/RelationSet.java | 45 ++ .../atlas/catalog/projection/TagRelation.java | 73 +++ .../atlas/catalog/projection/TraitRelation.java | 76 ++++ .../catalog/query/AlwaysQueryExpression.java | 46 ++ .../atlas/catalog/query/AtlasEntityQuery.java | 40 ++ .../catalog/query/AtlasEntityTagQuery.java | 73 +++ .../apache/atlas/catalog/query/AtlasQuery.java | 37 ++ .../atlas/catalog/query/AtlasTaxonomyQuery.java | 37 ++ .../atlas/catalog/query/AtlasTermQuery.java | 44 ++ .../apache/atlas/catalog/query/BaseQuery.java | 121 +++++ .../catalog/query/BaseQueryExpression.java | 105 +++++ .../catalog/query/BooleanQueryExpression.java | 141 ++++++ .../catalog/query/PrefixQueryExpression.java | 39 ++ .../query/ProjectionQueryExpression.java | 122 +++++ .../atlas/catalog/query/QueryExpression.java | 99 +++++ .../atlas/catalog/query/QueryFactory.java | 182 ++++++++ .../catalog/query/RegexQueryExpression.java | 41 ++ .../catalog/query/TermQueryExpression.java | 52 +++ .../catalog/query/TermRangeQueryExpression.java | 61 +++ .../catalog/query/WildcardQueryExpression.java | 43 ++ .../atlas/catalog/CollectionRequestTest.java | 74 ++++ .../atlas/catalog/DefaultDateFormatterTest.java | 41 ++ .../catalog/DefaultPropertyMapperTest.java | 177 ++++++++ .../catalog/EntityResourceProviderTest.java | 215 +++++++++ .../catalog/EntityTagResourceProviderTest.java | 444 +++++++++++++++++++ .../atlas/catalog/InstanceRequestTest.java | 67 +++ .../atlas/catalog/JsonSerializerTest.java | 120 +++++ .../atlas/catalog/ResourceComparatorTest.java | 61 +++ .../catalog/TaxonomyResourceProviderTest.java | 287 ++++++++++++ .../atlas/catalog/TermResourceProviderTest.java | 355 +++++++++++++++ .../apache/atlas/catalog/VertexWrapperTest.java | 311 +++++++++++++ .../EntityResourceDefinitionTest.java | 140 ++++++ .../EntityTagResourceDefinitionTest.java | 177 ++++++++ .../TaxonomyResourceDefinitionTest.java | 174 ++++++++ .../definition/TermResourceDefinitionTest.java | 210 +++++++++ .../query/AlwaysQueryExpressionTest.java | 74 ++++ .../atlas/catalog/query/QueryFactoryTest.java | 209 +++++++++ distro/src/conf/policy-store.txt | 10 +- pom.xml | 9 +- release-log.txt | 1 + .../atlas/services/DefaultMetadataService.java | 50 ++- .../apache/atlas/services/MetadataService.java | 28 ++ webapp/pom.xml | 5 + .../authorize/AtlasAuthorizationUtils.java | 25 +- .../atlas/authorize/AtlasResourceTypes.java | 2 +- .../apache/atlas/web/resources/BaseService.java | 126 ++++++ .../web/resources/CatalogExceptionMapper.java | 62 +++ .../CatalogRuntimeExceptionMapper.java | 78 ++++ .../atlas/web/resources/EntityService.java | 147 ++++++ .../atlas/web/resources/TaxonomyService.java | 201 +++++++++ webapp/src/main/webapp/WEB-INF/web.xml | 5 + .../authorize/AtlasAuthorizationUtilsTest.java | 121 +++++ 92 files changed, 8500 insertions(+), 27 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/pom.xml ---------------------------------------------------------------------- diff --git a/catalog/pom.xml b/catalog/pom.xml new file mode 100755 index 0000000..8a49d3d --- /dev/null +++ b/catalog/pom.xml @@ -0,0 +1,122 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF licenses this file + ~ to you under the Apache License, Version 2.0 (the + ~ "License"); you may not use this file except in compliance + ~ with the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="http://maven.apache.org/POM/4.0.0" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.atlas</groupId> + <artifactId>apache-atlas</artifactId> + <version>0.7-incubating-SNAPSHOT</version> + </parent> + <artifactId>atlas-catalog</artifactId> + <description>Apache Atlas Business Catalog Module</description> + <name>Apache Atlas Business Catalog</name> + <packaging>jar</packaging> + + <dependencies> + <dependency> + <groupId>org.apache.atlas</groupId> + <artifactId>atlas-repository</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.atlas</groupId> + <artifactId>atlas-typesystem</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.atlas</groupId> + <artifactId>atlas-server-api</artifactId> + </dependency> + + <dependency> + <groupId>joda-time</groupId> + <artifactId>joda-time</artifactId> + </dependency> + + <dependency> + <groupId>com.google.inject</groupId> + <artifactId>guice</artifactId> + </dependency> + + <dependency> + <groupId>com.google.inject.extensions</groupId> + <artifactId>guice-throwingproviders</artifactId> + </dependency> + + <dependency> + <groupId>com.google.inject.extensions</groupId> + <artifactId>guice-multibindings</artifactId> + </dependency> + + <dependency> + <groupId>com.googlecode.json-simple</groupId> + <artifactId>json-simple</artifactId> + </dependency> + + <dependency> + <groupId>com.tinkerpop.blueprints</groupId> + <artifactId>blueprints-core</artifactId> + </dependency> + + <dependency> + <groupId>com.tinkerpop.gremlin</groupId> + <artifactId>gremlin-java</artifactId> + </dependency> + + <!-- testing --> + <dependency> + <groupId>org.easymock</groupId> + <artifactId>easymock</artifactId> + <version>3.4</version> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.testng</groupId> + <artifactId>testng</artifactId> + </dependency> + + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-all</artifactId> + </dependency> + + </dependencies> + + <build> + + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <version>2.4</version> + <configuration> + <excludes> + <exclude>**/log4j.xml</exclude> + </excludes> + </configuration> + </plugin> + </plugins> + </build> +</project> http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/AtlasTypeSystem.java ---------------------------------------------------------------------- diff --git a/catalog/src/main/java/org/apache/atlas/catalog/AtlasTypeSystem.java b/catalog/src/main/java/org/apache/atlas/catalog/AtlasTypeSystem.java new file mode 100644 index 0000000..6f2e0be --- /dev/null +++ b/catalog/src/main/java/org/apache/atlas/catalog/AtlasTypeSystem.java @@ -0,0 +1,79 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.atlas.catalog; + +import org.apache.atlas.catalog.definition.ResourceDefinition; +import org.apache.atlas.catalog.exception.ResourceAlreadyExistsException; + +import java.util.Map; + +/** + * Abstraction for Atlas Type System. + */ +public interface AtlasTypeSystem { + + /** + * Create a Type in the Atlas Type System if it doesn't already exist. + * If the type already exists, this method has no affect. + * + * @param resourceDefinition resource definition for type being created + * @param name type name + * @param description description of the type being created + * + * @throws ResourceAlreadyExistsException if entity already exists + */ + void createClassType(ResourceDefinition resourceDefinition, String name, String description) + throws ResourceAlreadyExistsException; + + /** + * Create an entity in the Atlas Type System for the provided request and resource definition. + * If Type associated with the entity doesn't already exist, it is created. + * + * @param definition the definition of the resource for which we are creating the entity + * @param request the user request + * + * @throws ResourceAlreadyExistsException if type already exists + */ + void createEntity(ResourceDefinition definition, Request request) + throws ResourceAlreadyExistsException; + + /** + * Create a trait instance instance in the Atlas Type System. + * + * @param resourceDefinition resource definition for trait type being created + * @param name type name + * @param description description of the type being created + * + * @throws ResourceAlreadyExistsException if type already exists + */ + void createTraitType(ResourceDefinition resourceDefinition, String name, String description) + throws ResourceAlreadyExistsException; + + /** + * Create a trait instance in the Atlas Type System and associate it with the entity identified by the provided guid. + * + * @param guid id of the entity which will be associated with the trait instance + * @param typeName type name of the trait + * @param properties property map used to populate the trait instance + * + * @throws ResourceAlreadyExistsException if trait instance is already associated with the entity + */ + void createTraitInstance(String guid, String typeName, Map<String, Object> properties) + throws ResourceAlreadyExistsException; +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/BaseRequest.java ---------------------------------------------------------------------- diff --git a/catalog/src/main/java/org/apache/atlas/catalog/BaseRequest.java b/catalog/src/main/java/org/apache/atlas/catalog/BaseRequest.java new file mode 100644 index 0000000..f3376b0 --- /dev/null +++ b/catalog/src/main/java/org/apache/atlas/catalog/BaseRequest.java @@ -0,0 +1,62 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.atlas.catalog; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; + +/** + * Base user API request. + */ +public abstract class BaseRequest implements Request { + private final Map<String, Object> properties = new HashMap<>(); + private final String queryString; + private final Collection<String> additionalSelectProperties = new HashSet<>(); + + protected BaseRequest(Map<String, Object> properties, String queryString) { + if (properties != null) { + this.properties.putAll((properties)); + } + this.queryString = queryString; + } + + public Map<String, Object> getProperties() { + return properties; + } + + public <T> T getProperty(String name) { + return (T)properties.get(name); + } + + public String getQueryString() { + return queryString; + } + + @Override + public void addAdditionalSelectProperties(Collection<String> resultProperties) { + additionalSelectProperties.addAll(resultProperties); + } + + @Override + public Collection<String> getAdditionalSelectProperties() { + return additionalSelectProperties; + } +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/BaseResourceProvider.java ---------------------------------------------------------------------- diff --git a/catalog/src/main/java/org/apache/atlas/catalog/BaseResourceProvider.java b/catalog/src/main/java/org/apache/atlas/catalog/BaseResourceProvider.java new file mode 100644 index 0000000..517eaf6 --- /dev/null +++ b/catalog/src/main/java/org/apache/atlas/catalog/BaseResourceProvider.java @@ -0,0 +1,40 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.atlas.catalog; + +import org.apache.atlas.catalog.definition.ResourceDefinition; +import org.apache.atlas.catalog.query.QueryFactory; + +import java.util.*; + +/** + * Base class for resource providers. + */ +public abstract class BaseResourceProvider implements ResourceProvider { + protected AtlasTypeSystem typeSystem; + protected QueryFactory queryFactory = new QueryFactory(); + + protected BaseResourceProvider(AtlasTypeSystem typeSystem) { + this.typeSystem = typeSystem; + } + + protected void setQueryFactory(QueryFactory factory) { + queryFactory = factory; + } +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/CollectionRequest.java ---------------------------------------------------------------------- diff --git a/catalog/src/main/java/org/apache/atlas/catalog/CollectionRequest.java b/catalog/src/main/java/org/apache/atlas/catalog/CollectionRequest.java new file mode 100644 index 0000000..b1be1ae --- /dev/null +++ b/catalog/src/main/java/org/apache/atlas/catalog/CollectionRequest.java @@ -0,0 +1,35 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.atlas.catalog; + +import java.util.Map; + +/** + * A request for a collection resource. + */ +public class CollectionRequest extends BaseRequest { + public CollectionRequest(Map<String, Object> properties, String queryString) { + super(properties, queryString); + } + + @Override + public Cardinality getCardinality() { + return Cardinality.COLLECTION; + } +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/DefaultDateFormatter.java ---------------------------------------------------------------------- diff --git a/catalog/src/main/java/org/apache/atlas/catalog/DefaultDateFormatter.java b/catalog/src/main/java/org/apache/atlas/catalog/DefaultDateFormatter.java new file mode 100644 index 0000000..df07505 --- /dev/null +++ b/catalog/src/main/java/org/apache/atlas/catalog/DefaultDateFormatter.java @@ -0,0 +1,39 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.atlas.catalog; + +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.GregorianCalendar; + +/** + * Format a date field which is represented as a long. + */ +public class DefaultDateFormatter implements PropertyValueFormatter<Long, String> { + + //todo: obtain format from atlas proper + public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd:HH:mm:ss"); + + @Override + public String format(Long l) { + Calendar calendar = new GregorianCalendar(); + calendar.setTimeInMillis(l); + return DATE_FORMAT.format(calendar.getTime()); + } +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/DefaultPropertyMapper.java ---------------------------------------------------------------------- diff --git a/catalog/src/main/java/org/apache/atlas/catalog/DefaultPropertyMapper.java b/catalog/src/main/java/org/apache/atlas/catalog/DefaultPropertyMapper.java new file mode 100644 index 0000000..2f52b3b --- /dev/null +++ b/catalog/src/main/java/org/apache/atlas/catalog/DefaultPropertyMapper.java @@ -0,0 +1,142 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.atlas.catalog; + +import org.apache.atlas.AtlasException; +import org.apache.atlas.catalog.exception.CatalogRuntimeException; +import org.apache.atlas.repository.Constants; +import org.apache.atlas.typesystem.types.FieldMapping; +import org.apache.atlas.typesystem.types.HierarchicalType; +import org.apache.atlas.typesystem.types.TypeSystem; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * Default property mapper which translates property names to/from name exposed in API to internal fully qualified name. + */ +public class DefaultPropertyMapper implements PropertyMapper { + //todo: abstract HierarchicalType + private Map<String, HierarchicalType> typeInstances = new HashMap<>(); + private final Map<String, String> m_qualifiedToCleanMap = new HashMap<>(); + private final Map<String, String> m_cleanToQualifiedMap = new HashMap<>(); + + + public DefaultPropertyMapper() { + this(Collections.<String, String>emptyMap(), Collections.<String, String>emptyMap()); + } + + public DefaultPropertyMapper(Map<String, String> qualifiedToCleanMap, + Map<String, String> cleanToQualifiedMap) { + setDefaultMappings(); + + m_qualifiedToCleanMap.putAll(qualifiedToCleanMap); + m_cleanToQualifiedMap.putAll(cleanToQualifiedMap); + } + + @Override + public String toCleanName(String propName, String type) { + HierarchicalType dataType = getDataType(type); + String replacement = m_qualifiedToCleanMap.get(propName); + if (replacement == null && dataType != null) { + FieldMapping fieldMap = dataType.fieldMapping(); + if (! fieldMap.fields.containsKey(propName) && propName.contains(".")) { + String cleanName = propName.substring(propName.lastIndexOf('.') + 1); + if (fieldMap.fields.containsKey(cleanName)) { + replacement = cleanName; + } + } + } + + if (replacement == null) { + replacement = propName; + } + return replacement; + } + + @Override + public String toFullyQualifiedName(String propName, String type) { + HierarchicalType dataType = getDataType(type); + String replacement = m_cleanToQualifiedMap.get(propName); + if (replacement == null && dataType != null) { + FieldMapping fieldMap = dataType.fieldMapping(); + if (fieldMap.fields.containsKey(propName)) { + try { + replacement = dataType.getQualifiedName(propName); + } catch (AtlasException e) { + throw new CatalogRuntimeException(String.format( + "Unable to resolve fully qualified property name for type '%s': %s", type, e), e); + } + } + } + + if (replacement == null) { + replacement = propName; + } + return replacement; + } + + //todo: abstract this via AtlasTypeSystem + protected synchronized HierarchicalType getDataType(String type) { + HierarchicalType dataType = typeInstances.get(type); + //todo: are there still cases where type can be null? + if (dataType == null) { + dataType = createDataType(type); + typeInstances.put(type, dataType); + } + return dataType; + } + + protected HierarchicalType createDataType(String type) { + try { + return TypeSystem.getInstance().getDataType(HierarchicalType.class, type); + } catch (AtlasException e) { + throw new CatalogRuntimeException("Unable to get type instance from type system for type: " + type, e); + } + } + + private void setDefaultMappings() { + //todo: these are all internal "__*" properties + //todo: should be able to ask type system for the "clean" name for these + m_qualifiedToCleanMap.put(Constants.GUID_PROPERTY_KEY, "id"); + m_cleanToQualifiedMap.put("id", Constants.GUID_PROPERTY_KEY); + + m_qualifiedToCleanMap.put(Constants.TIMESTAMP_PROPERTY_KEY, "creation_time"); + m_cleanToQualifiedMap.put("creation_time", Constants.TIMESTAMP_PROPERTY_KEY); + + m_qualifiedToCleanMap.put(Constants.MODIFICATION_TIMESTAMP_PROPERTY_KEY, "modified_time"); + m_cleanToQualifiedMap.put("modified_time", Constants.MODIFICATION_TIMESTAMP_PROPERTY_KEY); + + m_qualifiedToCleanMap.put(Constants.ENTITY_TYPE_PROPERTY_KEY, "type"); + m_cleanToQualifiedMap.put("type", Constants.ENTITY_TYPE_PROPERTY_KEY); + + m_qualifiedToCleanMap.put(Constants.VERSION_PROPERTY_KEY, "version"); + m_cleanToQualifiedMap.put("version", Constants.VERSION_PROPERTY_KEY); + + m_qualifiedToCleanMap.put(Constants.TRAIT_NAMES_PROPERTY_KEY, "trait_names"); + m_cleanToQualifiedMap.put("trait_names", Constants.TRAIT_NAMES_PROPERTY_KEY); + + m_qualifiedToCleanMap.put(Constants.SUPER_TYPES_PROPERTY_KEY, "super_types"); + m_cleanToQualifiedMap.put("super_types", Constants.SUPER_TYPES_PROPERTY_KEY); + + m_qualifiedToCleanMap.put(Constants.STATE_PROPERTY_KEY, "state"); + m_cleanToQualifiedMap.put("state", Constants.STATE_PROPERTY_KEY); + } +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/DefaultTypeSystem.java ---------------------------------------------------------------------- diff --git a/catalog/src/main/java/org/apache/atlas/catalog/DefaultTypeSystem.java b/catalog/src/main/java/org/apache/atlas/catalog/DefaultTypeSystem.java new file mode 100644 index 0000000..f71c061 --- /dev/null +++ b/catalog/src/main/java/org/apache/atlas/catalog/DefaultTypeSystem.java @@ -0,0 +1,130 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.atlas.catalog; + +import org.apache.atlas.AtlasException; +import org.apache.atlas.catalog.definition.ResourceDefinition; +import org.apache.atlas.catalog.exception.CatalogRuntimeException; +import org.apache.atlas.catalog.exception.ResourceAlreadyExistsException; +import org.apache.atlas.services.MetadataService; +import org.apache.atlas.typesystem.ITypedReferenceableInstance; +import org.apache.atlas.typesystem.Referenceable; +import org.apache.atlas.typesystem.Struct; +import org.apache.atlas.typesystem.exception.EntityExistsException; +import org.apache.atlas.typesystem.exception.TypeExistsException; +import org.apache.atlas.typesystem.json.TypesSerialization; +import org.apache.atlas.typesystem.types.*; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; + +/** + * Default implementation. + */ +public class DefaultTypeSystem implements AtlasTypeSystem { + private final MetadataService metadataService; + + /** + * Constructor. + * + * @param metadataService atlas metadata service + */ + public DefaultTypeSystem(MetadataService metadataService) { + this.metadataService = metadataService; + } + + @Override + public void createEntity(ResourceDefinition definition, Request request) throws ResourceAlreadyExistsException { + String typeName = definition.getTypeName(); + try { + createClassType(definition, typeName, typeName + " Definition"); + } catch (ResourceAlreadyExistsException e) { + // ok if type already exists + } + try { + Referenceable entity = new Referenceable(typeName, request.getProperties()); + ITypedReferenceableInstance typedInstance = metadataService.getTypedReferenceableInstance(entity); + metadataService.createEntities(Collections.singletonList(typedInstance).toArray(new ITypedReferenceableInstance[1])); + } catch (EntityExistsException e) { + throw new ResourceAlreadyExistsException( + "Attempted to create an entity which already exists: " + request.getProperties()); + } catch (AtlasException e) { + throw new CatalogRuntimeException("An expected exception occurred creating an entity: " + e, e); + } + } + + @Override + public void createClassType(ResourceDefinition resourceDefinition, String name, String description) + throws ResourceAlreadyExistsException { + + createType(resourceDefinition.getPropertyDefinitions(), ClassType.class, name, description, false); + } + + @Override + public void createTraitType(ResourceDefinition resourceDefinition, String name, String description) + throws ResourceAlreadyExistsException { + + createType(resourceDefinition.getPropertyDefinitions(), TraitType.class, name, description, true); + } + + public void createTraitInstance(String guid, String typeName, Map<String, Object> properties) + throws ResourceAlreadyExistsException { + + try { + // not using the constructor with properties argument because it is marked 'InterfaceAudience.Private' + Struct struct = new Struct(typeName); + for (Map.Entry<String, Object> propEntry : properties.entrySet()) { + struct.set(propEntry.getKey(), propEntry.getValue()); + } + metadataService.addTrait(guid, metadataService.createTraitInstance(struct)); + } catch (IllegalArgumentException e) { + //todo: unfortunately, IllegalArgumentException can be thrown for other reasons + if (e.getMessage().contains("is already defined for entity")) { + throw new ResourceAlreadyExistsException( + String.format("Tag '%s' already associated with the entity", typeName)); + } else { + throw e; + } + } catch (AtlasException e) { + throw new CatalogRuntimeException(String.format( + "Unable to create trait instance '%s' in type system: %s", typeName, e), e); + } + } + + private <T extends HierarchicalType> void createType(Collection<AttributeDefinition> attributes, + Class<T> type, + String name, + String description, + boolean isTrait) + throws ResourceAlreadyExistsException { + + try { + HierarchicalTypeDefinition<T> definition = new HierarchicalTypeDefinition<>(type, name, description, null, + attributes.toArray(new AttributeDefinition[attributes.size()])); + + metadataService.createType(TypesSerialization.toJson(definition, isTrait)); + } catch (TypeExistsException e) { + throw new ResourceAlreadyExistsException(String.format("Type '%s' already exists", name)); + } catch (AtlasException e) { + throw new CatalogRuntimeException(String.format( + "Unable to create type '%s' in type system: %s", name, e), e); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/EntityResourceProvider.java ---------------------------------------------------------------------- diff --git a/catalog/src/main/java/org/apache/atlas/catalog/EntityResourceProvider.java b/catalog/src/main/java/org/apache/atlas/catalog/EntityResourceProvider.java new file mode 100644 index 0000000..c8d6f68 --- /dev/null +++ b/catalog/src/main/java/org/apache/atlas/catalog/EntityResourceProvider.java @@ -0,0 +1,72 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.atlas.catalog; + +import org.apache.atlas.catalog.definition.EntityResourceDefinition; +import org.apache.atlas.catalog.definition.ResourceDefinition; +import org.apache.atlas.catalog.exception.*; +import org.apache.atlas.catalog.query.AtlasQuery; + +import java.util.*; + +/** + * Provider for entity resources. + */ +public class EntityResourceProvider extends BaseResourceProvider implements ResourceProvider { + private final static ResourceDefinition resourceDefinition = new EntityResourceDefinition(); + + public EntityResourceProvider(AtlasTypeSystem typeSystem) { + super(typeSystem); + } + + @Override + public Result getResourceById(Request request) throws ResourceNotFoundException { + AtlasQuery atlasQuery; + try { + atlasQuery = queryFactory.createEntityQuery(request); + } catch (InvalidQueryException e) { + throw new CatalogRuntimeException("Unable to compile internal Entity query: " + e, e); + } + Collection<Map<String, Object>> results = atlasQuery.execute(); + if (results.isEmpty()) { + throw new ResourceNotFoundException(String.format("Entity '%s' not found.", + request.getProperty(resourceDefinition.getIdPropertyName()))); + } + return new Result(results); + } + + @Override + public Result getResources(Request request) throws InvalidQueryException, ResourceNotFoundException { + AtlasQuery atlasQuery = queryFactory.createEntityQuery(request); + return new Result(atlasQuery.execute()); + } + + @Override + public void createResource(Request request) + throws InvalidPayloadException, ResourceAlreadyExistsException, ResourceNotFoundException { + + // creation of entities is currently unsupported + throw new UnsupportedOperationException("Creation of entities is not currently supported"); + } + + @Override + public Collection<String> createResources(Request request) throws InvalidQueryException, ResourceNotFoundException { + throw new UnsupportedOperationException("Creation of entities is not currently supported"); + } +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/EntityTagResourceProvider.java ---------------------------------------------------------------------- diff --git a/catalog/src/main/java/org/apache/atlas/catalog/EntityTagResourceProvider.java b/catalog/src/main/java/org/apache/atlas/catalog/EntityTagResourceProvider.java new file mode 100644 index 0000000..dc4ab0d --- /dev/null +++ b/catalog/src/main/java/org/apache/atlas/catalog/EntityTagResourceProvider.java @@ -0,0 +1,135 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.atlas.catalog; + +import org.apache.atlas.catalog.definition.EntityTagResourceDefinition; +import org.apache.atlas.catalog.definition.ResourceDefinition; +import org.apache.atlas.catalog.exception.*; +import org.apache.atlas.catalog.query.AtlasQuery; + +import java.util.*; + +/** + * Provider for entity tag resources. + */ +public class EntityTagResourceProvider extends BaseResourceProvider implements ResourceProvider { + private final static ResourceDefinition resourceDefinition = new EntityTagResourceDefinition(); + private TermResourceProvider termResourceProvider; + + public EntityTagResourceProvider(AtlasTypeSystem typeSystem) { + super(typeSystem); + + } + + @Override + public Result getResourceById(Request request) throws ResourceNotFoundException { + AtlasQuery atlasQuery; + try { + atlasQuery = queryFactory.createEntityTagQuery(request); + } catch (InvalidQueryException e) { + throw new CatalogRuntimeException("Unable to compile internal Entity Tag query: " + e, e); + } + Collection<Map<String, Object>> results = atlasQuery.execute(); + if (results.isEmpty()) { + throw new ResourceNotFoundException(String.format("Tag '%s' not found.", + request.getProperty(resourceDefinition.getIdPropertyName()))); + } + + return new Result(results); + } + + @Override + public Result getResources(Request request) throws InvalidQueryException, ResourceNotFoundException { + AtlasQuery atlasQuery = queryFactory.createEntityTagQuery(request); + return new Result(atlasQuery.execute()); + } + + @Override + public void createResource(Request request) + throws InvalidPayloadException, ResourceAlreadyExistsException, ResourceNotFoundException { + + String entityId = String.valueOf(request.getProperties().remove("id")); + resourceDefinition.validate(request); + Result termResult = getTermQueryResult(request.<String>getProperty("name")); + Map<String, Object> termProperties = termResult.getPropertyMaps().iterator().next(); + //todo: use constant for property name + if (String.valueOf(termProperties.get("available_as_tag")).equals("false")) { + throw new InvalidPayloadException( + "Attempted to tag an entity with a term which is not available to be tagged"); + } + tagEntities(Collections.singleton(entityId), termProperties); + } + + //todo: response for case mixed case where some subset of creations fail + @Override + public Collection<String> createResources(Request request) + throws InvalidQueryException, ResourceNotFoundException, ResourceAlreadyExistsException { + + Collection<String> relativeUrls = new ArrayList<>(); + AtlasQuery atlasQuery = queryFactory.createEntityQuery(request); + Collection<String> guids = new ArrayList<>(); + for (Map<String, Object> entityMap: atlasQuery.execute()) { + guids.add(String.valueOf(entityMap.get("id"))); + } + + Collection<Map<String, String>> tagMaps = request.getProperty("tags"); + for (Map<String, String> tagMap : tagMaps) { + Result termResult = getTermQueryResult(tagMap.get("name")); + relativeUrls.addAll(tagEntities(guids, termResult.getPropertyMaps().iterator().next())); + } + return relativeUrls; + } + + private Result getTermQueryResult(String termName) throws ResourceNotFoundException { + Request tagRequest = new InstanceRequest( + Collections.<String, Object>singletonMap("termPath", new TermPath(termName))); + + tagRequest.addAdditionalSelectProperties(Collections.singleton("type")); + return getTermResourceProvider().getResourceById(tagRequest); + } + + private Collection<String> tagEntities(Collection<String> entityGuids, Map<String, Object> termProperties) + throws ResourceAlreadyExistsException { + + Collection<String> relativeUrls = new ArrayList<>(); + for (String guid : entityGuids) { + //createTermEdge(entity, Collections.singleton(termVertex)); + // copy term properties from trait associated with taxonomy to be set + // on trait associated with new entity (basically clone at time of tag event) + //todo: any changes to 'singleton' trait won't be reflected in new trait + //todo: iterate over properties in term definition instead of hard coding here + Map<String, Object> properties = new HashMap<>(); + String termName = String.valueOf(termProperties.get("name")); + properties.put("name", termName); + properties.put("description", termProperties.get("description")); + + typeSystem.createTraitInstance(guid, termName, properties); + //todo: *** shouldn't know anything about href structure in this class *** + relativeUrls.add(String.format("v1/entities/%s/tags/%s", guid, termName)); + } + return relativeUrls; + } + + protected synchronized ResourceProvider getTermResourceProvider() { + if (termResourceProvider == null) { + termResourceProvider = new TermResourceProvider(typeSystem); + } + return termResourceProvider; + } +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/InstanceRequest.java ---------------------------------------------------------------------- diff --git a/catalog/src/main/java/org/apache/atlas/catalog/InstanceRequest.java b/catalog/src/main/java/org/apache/atlas/catalog/InstanceRequest.java new file mode 100644 index 0000000..01583c4 --- /dev/null +++ b/catalog/src/main/java/org/apache/atlas/catalog/InstanceRequest.java @@ -0,0 +1,35 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.atlas.catalog; + +import java.util.Map; + +/** + * A request for an instance resource. + */ +public class InstanceRequest extends BaseRequest { + public InstanceRequest(Map<String, Object> properties) { + super(properties, null); + } + + @Override + public Cardinality getCardinality() { + return Cardinality.INSTANCE; + } +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/JsonSerializer.java ---------------------------------------------------------------------- diff --git a/catalog/src/main/java/org/apache/atlas/catalog/JsonSerializer.java b/catalog/src/main/java/org/apache/atlas/catalog/JsonSerializer.java new file mode 100644 index 0000000..a75639f --- /dev/null +++ b/catalog/src/main/java/org/apache/atlas/catalog/JsonSerializer.java @@ -0,0 +1,90 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.atlas.catalog; + +import com.google.gson.stream.JsonWriter; +import org.apache.atlas.catalog.exception.CatalogRuntimeException; + +import javax.ws.rs.core.UriInfo; +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * JSON serializer. + */ +public class JsonSerializer { + public String serialize(Result result, UriInfo ui) { + Writer json = new StringWriter(); + JsonWriter writer = new JsonWriter(json); + writer.setIndent(" "); + + try { + writeValue(writer, result.getPropertyMaps(), ui.getBaseUri().toASCIIString()); + } catch (IOException e) { + throw new CatalogRuntimeException("Unable to write JSON response.", e); + } + return json.toString(); + } + + private void writeValue(JsonWriter writer, Object value, String baseUrl) throws IOException { + if (value == null) { + writer.nullValue(); + } else if (value instanceof Map) { + writer.beginObject(); + LinkedHashMap<String, Object> nonScalarMap = new LinkedHashMap<>(); + for (Map.Entry<String, Object> entry : ((Map<String, Object>) value).entrySet()) { + String key = entry.getKey(); + Object val = entry.getValue(); + + if (val == null || ! (val instanceof Collection || val instanceof Map)) { + //todo: use a token in value instead of prop name + if (key.equals("href")) { + val = baseUrl + String.valueOf(val); + } + writer.name(key); + writeValue(writer, val, baseUrl); + } else { + nonScalarMap.put(key, val); + } + } + for (Map.Entry<String, Object> entry : nonScalarMap.entrySet()) { + writer.name(entry.getKey()); + writeValue(writer, entry.getValue(), baseUrl); + } + writer.endObject(); + } else if (value instanceof Collection) { + writer.beginArray(); + for (Object o : (Collection) value) { + writeValue(writer, o, baseUrl); + } + writer.endArray(); + } else if (value instanceof Number) { + writer.value((Number) value); + } else if (value instanceof Boolean) { + writer.value((Boolean) value); + } else { + // everything else is String + writer.value(String.valueOf(value)); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/PropertyMapper.java ---------------------------------------------------------------------- diff --git a/catalog/src/main/java/org/apache/atlas/catalog/PropertyMapper.java b/catalog/src/main/java/org/apache/atlas/catalog/PropertyMapper.java new file mode 100644 index 0000000..50ee275 --- /dev/null +++ b/catalog/src/main/java/org/apache/atlas/catalog/PropertyMapper.java @@ -0,0 +1,45 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.atlas.catalog; + + +/** + * Translates property names to/from name exposed in API to internal fully qualified name. + */ +public interface PropertyMapper { + /** + * Translate a qualified name to a clean name. + * + * @param propName property name to translate + * @param type resource type + * + * @return clean property name + */ + String toCleanName(String propName, String type); + + /** + * Translate a clean name to a fully qualified name. + * + * @param propName property name to translate + * @param type resource type + * + * @return fully qualified property name + */ + String toFullyQualifiedName(String propName, String type); +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/PropertyValueFormatter.java ---------------------------------------------------------------------- diff --git a/catalog/src/main/java/org/apache/atlas/catalog/PropertyValueFormatter.java b/catalog/src/main/java/org/apache/atlas/catalog/PropertyValueFormatter.java new file mode 100644 index 0000000..a42f528 --- /dev/null +++ b/catalog/src/main/java/org/apache/atlas/catalog/PropertyValueFormatter.java @@ -0,0 +1,33 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.atlas.catalog; + +/** + * A rule for translating a property value. + */ +public interface PropertyValueFormatter <T,V> { + /** + * Format a property value. + * + * @param value property value to format + * + * @return formatted property value + */ + V format(T value); +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/Request.java ---------------------------------------------------------------------- diff --git a/catalog/src/main/java/org/apache/atlas/catalog/Request.java b/catalog/src/main/java/org/apache/atlas/catalog/Request.java new file mode 100644 index 0000000..7dc781a --- /dev/null +++ b/catalog/src/main/java/org/apache/atlas/catalog/Request.java @@ -0,0 +1,77 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.atlas.catalog; + +import java.util.Collection; +import java.util.Map; + +/** + * Represents a user request. + */ +public interface Request { + /** + * Request cardinality enum. + */ + enum Cardinality {INSTANCE, COLLECTION} + + /** + * Get request properties. + * + * @return request property map + */ + Map<String, Object> getProperties(); + + /** + * Get the value of a specified property. + * + * @param name property name + * @param <T> value type + * + * @return value for the requested property or null if property not in map + */ + <T> T getProperty(String name); + + /** + * Get the query string. + * + * @return the user specified query string or null + */ + String getQueryString(); + + /** + * Get the cardinality of the request. + * + * @return the request cardinality + */ + Cardinality getCardinality(); + + /** + * Add additional property names which should be returned in the result. + * + * @param resultProperties collection of property names + */ + void addAdditionalSelectProperties(Collection<String> resultProperties); + + /** + * Get any additional property names which should be included in the result. + * + * @return collection of added property names or an empty collection + */ + Collection<String> getAdditionalSelectProperties(); +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/ResourceComparator.java ---------------------------------------------------------------------- diff --git a/catalog/src/main/java/org/apache/atlas/catalog/ResourceComparator.java b/catalog/src/main/java/org/apache/atlas/catalog/ResourceComparator.java new file mode 100644 index 0000000..deb2e4c --- /dev/null +++ b/catalog/src/main/java/org/apache/atlas/catalog/ResourceComparator.java @@ -0,0 +1,62 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.atlas.catalog; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +/** + * Provides key ordering for resource property maps. + * Ordering can be defined explicitly for specific properties, + * otherwise natural ordering is used. + */ +public class ResourceComparator implements Comparator<String> { + private static List<String> ordering = new ArrayList<>(); + + @Override + public int compare(String s1, String s2) { + if (s1.equals(s2)) { + return 0; + } + + int s1Order = ordering.indexOf(s1); + int s2Order = ordering.indexOf(s2); + + if (s1Order == -1 && s2Order == -1) { + return s1.compareTo(s2); + } + + if (s1Order != -1 && s2Order != -1) { + return s1Order - s2Order; + } + + return s1Order == -1 ? 1 : -1; + + } + + //todo: each resource definition can provide its own ordering list + static { + ordering.add("href"); + ordering.add("name"); + ordering.add("id"); + ordering.add("description"); + ordering.add("type"); + } +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/ResourceProvider.java ---------------------------------------------------------------------- diff --git a/catalog/src/main/java/org/apache/atlas/catalog/ResourceProvider.java b/catalog/src/main/java/org/apache/atlas/catalog/ResourceProvider.java new file mode 100644 index 0000000..4c4319c --- /dev/null +++ b/catalog/src/main/java/org/apache/atlas/catalog/ResourceProvider.java @@ -0,0 +1,75 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.atlas.catalog; + +import org.apache.atlas.catalog.exception.*; + +import java.util.Collection; + +/** + * Provider for a resource type. + */ +public interface ResourceProvider { + /** + * Get a resource by primary key. + * + * @param request request instance which contains the required id properties and no query string + * @return result containing the requested resource; never null + * + * @throws ResourceNotFoundException if the requested resource isn't found + */ + Result getResourceById(Request request) throws ResourceNotFoundException; + + /** + * Get all resources which match the provider query. + * + * @param request request instance which will include a query string and possibly properties + * @return result containing collection of matching resources. If no resources match + * a result is returned with no resources + * + * @throws InvalidQueryException if the user query contains invalid syntax + * @throws ResourceNotFoundException if a parent resource of the requested resource doesn't exist + */ + Result getResources(Request request) throws InvalidQueryException, ResourceNotFoundException; + + /** + * Create a single resource. + * + * @param request request instance containing the contents of the resource to create + * + * @throws InvalidPayloadException if the payload or any other part of the user request is invalid + * @throws ResourceAlreadyExistsException if the resource already exists + * @throws ResourceNotFoundException if a parent of the resource to create doesn't exist + */ + void createResource(Request request) + throws InvalidPayloadException, ResourceAlreadyExistsException, ResourceNotFoundException; + + //todo: define the behavior for partial success + /** + * Create multiple resources. + * + * @param request request instance containing the contents of 1..n resources + * @return collection of relative urls for the created resources + * + * @throws InvalidPayloadException if the payload or any other part of the user request is invalid + * @throws ResourceAlreadyExistsException if the resource already exists + * @throws ResourceNotFoundException if a parent of the resource to create doesn't exist + */ + Collection<String> createResources(Request request) throws CatalogException; +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/Result.java ---------------------------------------------------------------------- diff --git a/catalog/src/main/java/org/apache/atlas/catalog/Result.java b/catalog/src/main/java/org/apache/atlas/catalog/Result.java new file mode 100644 index 0000000..34a81ab --- /dev/null +++ b/catalog/src/main/java/org/apache/atlas/catalog/Result.java @@ -0,0 +1,50 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.atlas.catalog; + +import java.util.Collection; +import java.util.Map; + +/** + * Resource provider result. + */ +public class Result { + /** + * collection of property maps + */ + private Collection<Map<String, Object>> propertyMaps; + + /** + * Constructor. + * + * @param propertyMaps collection of property maps + */ + public Result(Collection<Map<String, Object>> propertyMaps) { + this.propertyMaps = propertyMaps; + } + + /** + * Obtain the result property maps. + * + * @return result property maps + */ + public Collection<Map<String, Object>> getPropertyMaps() { + return propertyMaps; + } +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/TaxonomyResourceProvider.java ---------------------------------------------------------------------- diff --git a/catalog/src/main/java/org/apache/atlas/catalog/TaxonomyResourceProvider.java b/catalog/src/main/java/org/apache/atlas/catalog/TaxonomyResourceProvider.java new file mode 100644 index 0000000..7a46f5d --- /dev/null +++ b/catalog/src/main/java/org/apache/atlas/catalog/TaxonomyResourceProvider.java @@ -0,0 +1,80 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.atlas.catalog; + +import org.apache.atlas.catalog.definition.ResourceDefinition; +import org.apache.atlas.catalog.definition.TaxonomyResourceDefinition; +import org.apache.atlas.catalog.exception.*; +import org.apache.atlas.catalog.query.AtlasQuery; + +import java.util.*; + +/** + * Provider for taxonomy resources. + */ +public class TaxonomyResourceProvider extends BaseResourceProvider implements ResourceProvider { + private static final ResourceDefinition resourceDefinition = new TaxonomyResourceDefinition(); + public TaxonomyResourceProvider(AtlasTypeSystem typeSystem) { + super(typeSystem); + } + + @Override + public Result getResourceById(Request request) throws ResourceNotFoundException { + AtlasQuery atlasQuery; + try { + atlasQuery = queryFactory.createTaxonomyQuery(request); + } catch (InvalidQueryException e) { + throw new CatalogRuntimeException("Unable to compile internal Taxonomy query: " + e, e); + } + Collection<Map<String, Object>> results = atlasQuery.execute(); + if (results.isEmpty()) { + throw new ResourceNotFoundException(String.format("Taxonomy '%s' not found.", + request.getProperty(resourceDefinition.getIdPropertyName()))); + } + return new Result(results); + } + + public Result getResources(Request request) throws InvalidQueryException, ResourceNotFoundException { + AtlasQuery atlasQuery = queryFactory.createTaxonomyQuery(request); + return new Result(atlasQuery.execute()); + } + + public synchronized void createResource(Request request) + throws InvalidPayloadException, ResourceAlreadyExistsException { + + resourceDefinition.validate(request); + ensureTaxonomyDoesntExist(request); + typeSystem.createEntity(resourceDefinition, request); + } + + @Override + public Collection<String> createResources(Request request) throws InvalidQueryException, ResourceNotFoundException { + throw new UnsupportedOperationException("Creating multiple Taxonomies in a request is not currently supported"); + } + + private void ensureTaxonomyDoesntExist(Request request) throws ResourceAlreadyExistsException { + try { + getResourceById(request); + throw new ResourceAlreadyExistsException(String.format("Taxonomy '%s' already exists.", + request.getProperty("name"))); + } catch (ResourceNotFoundException e) { + // expected case + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/TermPath.java ---------------------------------------------------------------------- diff --git a/catalog/src/main/java/org/apache/atlas/catalog/TermPath.java b/catalog/src/main/java/org/apache/atlas/catalog/TermPath.java new file mode 100644 index 0000000..3252227 --- /dev/null +++ b/catalog/src/main/java/org/apache/atlas/catalog/TermPath.java @@ -0,0 +1,111 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.atlas.catalog; + +/** + * Term path information. + */ +//todo: split between Term and TermPath +public class TermPath { + private final String m_taxonomy; + private final String m_fqn; + private final String m_name; + private final String[] m_paths; + + public TermPath(String fullyQualifiedName) { + m_fqn = fullyQualifiedName; + //todo: validation + int idx = fullyQualifiedName.indexOf('.'); + if (idx != -1) { + m_taxonomy = fullyQualifiedName.substring(0, idx); + m_name = fullyQualifiedName.substring(idx + 1); + m_paths = m_name.split("\\."); + } else { + m_taxonomy = fullyQualifiedName; + m_name = null; + m_paths = new String[0]; + } + } + + public TermPath(String taxonomyName, String termName) { + m_taxonomy = taxonomyName; + m_name = termName != null && termName.isEmpty() ? null : termName; + + if (m_name != null) { + m_fqn = String.format("%s.%s", taxonomyName, termName); + m_paths = termName.split("\\."); + } else { + m_fqn = taxonomyName; + m_paths = new String[0]; + } + } + + /** + * Get the absolute term name which is in the form of TAXONOMY_NAME.TERM_NAME + * + * @return absolute term name which includes the taxonomy name + */ + public String getFullyQualifiedName() { + return m_fqn; + } + + /** + * Get the term name. This differs from the absolute name in that it doesn't + * include the taxonomy name. + * + * @return the term name + */ + public String getName() { + return m_name; + } + + /** + * Get the short name for the term which doesn't include any taxonomy or parent information. + * @return term short name + */ + public String getShortName() { + return m_paths[m_paths.length - 1]; + } + + public String getPath() { + if (m_name == null) { + return "/"; + } else { + int idx = m_fqn.indexOf('.'); + int lastIdx = m_fqn.lastIndexOf('.'); + + return idx == lastIdx ? "/" : + m_fqn.substring(idx, lastIdx).replaceAll("\\.", "/"); + } + } + + public TermPath getParent() { + //todo: if this is the root path, throw exception + return new TermPath(m_taxonomy, m_name.substring(0, m_name.lastIndexOf('.'))); + } + + + public String getTaxonomyName() { + return m_taxonomy; + } + + public String[] getPathSegments() { + return m_paths; + } +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/TermResourceProvider.java ---------------------------------------------------------------------- diff --git a/catalog/src/main/java/org/apache/atlas/catalog/TermResourceProvider.java b/catalog/src/main/java/org/apache/atlas/catalog/TermResourceProvider.java new file mode 100644 index 0000000..431b06d --- /dev/null +++ b/catalog/src/main/java/org/apache/atlas/catalog/TermResourceProvider.java @@ -0,0 +1,128 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.atlas.catalog; + +import org.apache.atlas.catalog.definition.ResourceDefinition; +import org.apache.atlas.catalog.definition.TermResourceDefinition; +import org.apache.atlas.catalog.exception.*; +import org.apache.atlas.catalog.query.AtlasQuery; + +import java.util.*; + +/** + * Provider for Term resources. + */ +public class TermResourceProvider extends BaseResourceProvider implements ResourceProvider { + private final static ResourceDefinition resourceDefinition = new TermResourceDefinition(); + private TaxonomyResourceProvider taxonomyResourceProvider; + + public TermResourceProvider(AtlasTypeSystem typeSystem) { + super(typeSystem); + } + + @Override + public Result getResourceById(Request request) throws ResourceNotFoundException { + //todo: shouldn't need to add this here + request.getProperties().put("name", request.<TermPath>getProperty("termPath").getFullyQualifiedName()); + AtlasQuery atlasQuery; + try { + atlasQuery = queryFactory.createTermQuery(request); + } catch (InvalidQueryException e) { + throw new CatalogRuntimeException("Unable to compile internal Term query: " + e, e); + } + Collection<Map<String, Object>> results = atlasQuery.execute(); + if (results.isEmpty()) { + throw new ResourceNotFoundException(String.format("Term '%s' not found.", + request.<TermPath>getProperty("termPath").getFullyQualifiedName())); + } + return new Result(results); + } + + public Result getResources(Request request) + throws InvalidQueryException, ResourceNotFoundException { + + TermPath termPath = request.getProperty("termPath"); + String queryString = doQueryStringConversions(termPath, request.getQueryString()); + Request queryRequest = new CollectionRequest(request.getProperties(), queryString); + AtlasQuery atlasQuery = queryFactory.createTermQuery(queryRequest); + Collection<Map<String, Object>> result = atlasQuery.execute(); + return new Result(result); + } + + public void createResource(Request request) + throws InvalidPayloadException, ResourceAlreadyExistsException, ResourceNotFoundException { + + TermPath termPath = (TermPath) request.getProperties().remove("termPath"); + String qualifiedTermName = termPath.getFullyQualifiedName(); + request.getProperties().put("name", qualifiedTermName); + resourceDefinition.validate(request); + + // get taxonomy + Request taxonomyRequest = new InstanceRequest( + Collections.<String, Object>singletonMap("name", termPath.getTaxonomyName())); + taxonomyRequest.addAdditionalSelectProperties(Collections.singleton("id")); + Result taxonomyResult = getTaxonomyResourceProvider().getResourceById(taxonomyRequest); + Map<String, Object> taxonomyPropertyMap = taxonomyResult.getPropertyMaps().iterator().next(); + + // ensure that parent exists if not a root level term + if (! termPath.getPath().equals("/")) { + Map<String, Object> parentProperties = new HashMap<>(request.getProperties()); + parentProperties.put("termPath", termPath.getParent()); + getResourceById(new InstanceRequest(parentProperties)); + } + + typeSystem.createTraitType(resourceDefinition, qualifiedTermName, + request.<String>getProperty("description")); + + typeSystem.createTraitInstance(String.valueOf(taxonomyPropertyMap.get("id")), + qualifiedTermName, request.getProperties()); + } + + @Override + public Collection<String> createResources(Request request) throws InvalidQueryException, ResourceNotFoundException { + throw new UnsupportedOperationException("Creating multiple Terms in a request is not currently supported"); + } + + //todo: add generic support for pre-query modification of expected value + //todo: similar path parsing code is used in several places in this class + private String doQueryStringConversions(TermPath termPath, String queryStr) throws InvalidQueryException { + String hierarchyPathProp = "hierarchy/path"; + // replace "." + if (queryStr != null && queryStr.contains(String.format("%s:.", hierarchyPathProp))) { + //todo: regular expression replacement + queryStr = queryStr.replaceAll(String.format("%s:.", hierarchyPathProp), + String.format("%s:%s", hierarchyPathProp, termPath.getPath())); + } + return queryStr; + } + + protected synchronized ResourceProvider getTaxonomyResourceProvider() { + if (taxonomyResourceProvider == null) { + taxonomyResourceProvider = new TaxonomyResourceProvider(typeSystem); + } + return taxonomyResourceProvider; + } +} + + + + + + + http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/TermVertexWrapper.java ---------------------------------------------------------------------- diff --git a/catalog/src/main/java/org/apache/atlas/catalog/TermVertexWrapper.java b/catalog/src/main/java/org/apache/atlas/catalog/TermVertexWrapper.java new file mode 100644 index 0000000..d60e3f3 --- /dev/null +++ b/catalog/src/main/java/org/apache/atlas/catalog/TermVertexWrapper.java @@ -0,0 +1,36 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.atlas.catalog; + +import com.tinkerpop.blueprints.Vertex; +import org.apache.atlas.catalog.definition.EntityTagResourceDefinition; +import org.apache.atlas.catalog.definition.ResourceDefinition; +import org.apache.atlas.repository.Constants; + +import java.util.Collections; + +/** + * Wrapper for term vertices. + */ +public class TermVertexWrapper extends VertexWrapper { + + public TermVertexWrapper(Vertex v) { + super(v, new EntityTagResourceDefinition()); + } +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aaf2971a/catalog/src/main/java/org/apache/atlas/catalog/VertexWrapper.java ---------------------------------------------------------------------- diff --git a/catalog/src/main/java/org/apache/atlas/catalog/VertexWrapper.java b/catalog/src/main/java/org/apache/atlas/catalog/VertexWrapper.java new file mode 100644 index 0000000..6e5d28e --- /dev/null +++ b/catalog/src/main/java/org/apache/atlas/catalog/VertexWrapper.java @@ -0,0 +1,111 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.atlas.catalog; + +import com.tinkerpop.blueprints.Vertex; +import org.apache.atlas.catalog.definition.ResourceDefinition; +import org.apache.atlas.repository.Constants; + +import java.util.*; + +/** + * Wrapper for vertices which provides additional information. + */ +public class VertexWrapper { + private final Vertex vertex; + private final String vertexType; + private final Set<String> removedProperties = new HashSet<>(); + private final PropertyMapper propertyMapper; + private final Map<String, PropertyValueFormatter> propertyValueFormatters; + protected ResourceComparator resourceComparator = new ResourceComparator(); + + public VertexWrapper(Vertex v, ResourceDefinition resourceDefinition) { + this(v, resourceDefinition.getPropertyMapper(), resourceDefinition.getPropertyValueFormatters()); + } + + public VertexWrapper(Vertex v, + PropertyMapper mapper, + Map<String, PropertyValueFormatter> formatters) { + vertex = v; + vertexType = getVertexType(v); + propertyMapper = mapper; + propertyValueFormatters = formatters; + } + + public Vertex getVertex() { + return vertex; + } + + public <T> T getProperty(String name) { + T val; + if (removedProperties.contains(name)) { + val = null; + } else { + val = vertex.getProperty(propertyMapper.toFullyQualifiedName(name, vertexType)); + if (propertyValueFormatters.containsKey(name)) { + //todo: fix typing of property mapper + val = (T) propertyValueFormatters.get(name).format(val); + } + } + return val; + } + + public Collection<String> getPropertyKeys() { + Collection<String> propertyKeys = new TreeSet<>(resourceComparator); + + for (String p : vertex.getPropertyKeys()) { + String cleanName = propertyMapper.toCleanName(p, vertexType); + if (! removedProperties.contains(cleanName)) { + propertyKeys.add(cleanName); + } + } + return propertyKeys; + } + + public Map<String, Object> getPropertyMap() { + Map<String, Object> props = new TreeMap<>(resourceComparator); + for (String p : vertex.getPropertyKeys()) { + String cleanName = propertyMapper.toCleanName(p, vertexType); + if (! removedProperties.contains(cleanName)) { + Object val = vertex.getProperty(p); + if (propertyValueFormatters.containsKey(cleanName)) { + val = propertyValueFormatters.get(cleanName).format(val); + } + props.put(cleanName, val); + } + } + return props; + } + + public void removeProperty(String name) { + removedProperties.add(name); + } + + public boolean isPropertyRemoved(String name) { + return removedProperties.contains(name); + } + + public String toString() { + return String.format("VertexWrapper[name=%s]", getProperty("name")); + } + + private String getVertexType(Vertex v) { + return v.getProperty(Constants.ENTITY_TYPE_PROPERTY_KEY); + } +}
