/** * 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.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import org.apache.atlas.AtlasErrorCode; 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.catalog.exception.ResourceNotFoundException; import org.apache.atlas.classification.InterfaceAudience; import org.apache.atlas.exception.AtlasBaseException; import org.apache.atlas.model.typedef.AtlasClassificationDef; import org.apache.atlas.model.typedef.AtlasEntityDef; import org.apache.atlas.model.typedef.AtlasEnumDef; import org.apache.atlas.model.typedef.AtlasStructDef; import org.apache.atlas.model.typedef.AtlasTypesDef; import org.apache.atlas.repository.converters.TypeConverterUtil; import org.apache.atlas.services.MetadataService; import org.apache.atlas.store.AtlasTypeDefStore; import org.apache.atlas.type.AtlasTypeUtil; 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.EntityNotFoundException; import org.apache.atlas.typesystem.exception.TraitNotFoundException; import org.apache.atlas.typesystem.types.AttributeDefinition; import org.apache.atlas.typesystem.types.ClassType; import org.apache.atlas.typesystem.types.HierarchicalType; import org.apache.atlas.typesystem.types.TraitType; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; /** * Default implementation. */ public class DefaultTypeSystem implements AtlasTypeSystem { private final MetadataService metadataService; private final AtlasTypeDefStore typeDefStore; /** * Constructor. * * @param metadataService atlas metadata service */ public DefaultTypeSystem(MetadataService metadataService, AtlasTypeDefStore typeDefStore) throws AtlasBaseException { this.metadataService = metadataService; this.typeDefStore = typeDefStore; //Create namespace createSuperTypes(); } @InterfaceAudience.Private private void createSuperTypes() throws AtlasBaseException { AtlasClassificationDef termClassification = AtlasTypeUtil.createTraitTypeDef(TaxonomyResourceProvider.TAXONOMY_TERM_TYPE, TaxonomyResourceProvider.TAXONOMY_TERM_TYPE, ImmutableSet.<String>of(), AtlasTypeUtil.createOptionalAttrDef(TaxonomyResourceProvider.NAMESPACE_ATTRIBUTE_NAME, "string")); createTraitType(termClassification); } private void createTraitType(AtlasClassificationDef classificationDef) throws AtlasBaseException { try { typeDefStore.getClassificationDefByName(classificationDef.getName()); } catch (AtlasBaseException tne) { //Type not found . Create if (tne.getAtlasErrorCode() == AtlasErrorCode.TYPE_NAME_NOT_FOUND) { AtlasTypesDef typesDef = new AtlasTypesDef(ImmutableList.<AtlasEnumDef>of(), ImmutableList.<AtlasStructDef>of(), ImmutableList.of(classificationDef), ImmutableList.<AtlasEntityDef>of()); typeDefStore.createTypesDef(typesDef); } else { throw tne; } } } @Override public String 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.getQueryProperties()); //add Taxonomy Namespace entity.set(TaxonomyResourceProvider.NAMESPACE_ATTRIBUTE_NAME, TaxonomyResourceProvider.TAXONOMY_NS); ITypedReferenceableInstance typedInstance = metadataService.getTypedReferenceableInstance(entity); ITypedReferenceableInstance[] entitiesToCreate = Collections.singletonList(typedInstance).toArray(new ITypedReferenceableInstance[1]); final List<String> entities = metadataService.createEntities(entitiesToCreate).getCreatedEntities(); return entities != null && entities.size() > 0 ? entities.get(0) : null; } catch (EntityExistsException e) { throw new ResourceAlreadyExistsException( "Attempted to create an entity which already exists: " + request.getQueryProperties()); } catch (AtlasException e) { throw new CatalogRuntimeException("An expected exception occurred creating an entity: " + e, e); } } @Override public void deleteEntity(ResourceDefinition definition, Request request) throws ResourceNotFoundException { String typeName = definition.getTypeName(); String cleanIdPropName = definition.getIdPropertyName(); String idValue = request.getProperty(cleanIdPropName); try { // transaction handled by atlas repository metadataService.deleteEntityByUniqueAttribute(typeName, cleanIdPropName, idValue); } catch (EntityNotFoundException e) { throw new ResourceNotFoundException(String.format("The specified entity doesn't exist: type=%s, %s=%s", typeName, cleanIdPropName, idValue)); } catch (AtlasException e) { throw new CatalogRuntimeException(String.format( "An unexpected error occurred while attempting to delete entity: type=%s, %s=%s : %s", typeName, cleanIdPropName, idValue, 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); } @Override 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()); } //add Taxonomy Namespace struct.set(TaxonomyResourceProvider.NAMESPACE_ATTRIBUTE_NAME, TaxonomyResourceProvider.TAXONOMY_NS); 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); } } @Override public void deleteTag(String guid, String traitName) throws ResourceNotFoundException { try { metadataService.deleteTrait(guid, traitName); } catch (TraitNotFoundException e) { throw new ResourceNotFoundException(String.format( "The trait '%s' doesn't exist for entity '%s'", traitName, guid)); } catch (AtlasException e) { throw new CatalogRuntimeException(String.format( "Unable to delete tag '%s' from entity '%s'", traitName, guid), e); } } private <T extends HierarchicalType> void createType(Collection<AttributeDefinition> attributes, Class<T> type, String name, String description, boolean isTrait) throws ResourceAlreadyExistsException { try { List<AtlasStructDef.AtlasAttributeDef> attrDefs = new ArrayList<>(); for (AttributeDefinition attrDefinition : attributes) { attrDefs.add(TypeConverterUtil.toAtlasAttributeDef(attrDefinition)); } if ( isTrait) { AtlasClassificationDef classificationDef = new AtlasClassificationDef(name, description, "1.0", attrDefs, ImmutableSet.of(TaxonomyResourceProvider.TAXONOMY_TERM_TYPE)); AtlasTypesDef typesDef = new AtlasTypesDef(ImmutableList.<AtlasEnumDef>of(), ImmutableList.<AtlasStructDef>of(), ImmutableList.of(classificationDef), ImmutableList.<AtlasEntityDef>of()); typeDefStore.createTypesDef(typesDef); } else { AtlasEntityDef entityDef = new AtlasEntityDef(name, description, "1.0", attrDefs); AtlasTypesDef typesDef = new AtlasTypesDef(ImmutableList.<AtlasEnumDef>of(), ImmutableList.<AtlasStructDef>of(), ImmutableList.<AtlasClassificationDef>of(), ImmutableList.of(entityDef)); typeDefStore.createTypesDef(typesDef); } } catch (AtlasBaseException e) { if ( e.getAtlasErrorCode() == AtlasErrorCode.TYPE_ALREADY_EXISTS) { throw new ResourceAlreadyExistsException(String.format("Type '%s' already exists", name)); } else { throw new CatalogRuntimeException(String.format( "Unable to create type '%s' in type system: %s", name, e), e); } } } }