| /** |
| * 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. |
| */ |
| package org.apache.atlas.repository.converters; |
| |
| import com.google.inject.Inject; |
| import com.google.inject.Singleton; |
| import org.apache.atlas.AtlasClient; |
| import org.apache.atlas.AtlasClient.EntityResult; |
| import org.apache.atlas.AtlasErrorCode; |
| import org.apache.atlas.AtlasException; |
| import org.apache.atlas.CreateUpdateEntitiesResult; |
| import org.apache.atlas.exception.AtlasBaseException; |
| import org.apache.atlas.model.TypeCategory; |
| import org.apache.atlas.model.instance.AtlasClassification; |
| import org.apache.atlas.model.instance.AtlasEntity; |
| import org.apache.atlas.model.instance.AtlasEntity.AtlasEntitiesWithExtInfo; |
| import org.apache.atlas.model.instance.AtlasEntityHeader; |
| import org.apache.atlas.model.instance.EntityMutationResponse; |
| import org.apache.atlas.model.instance.EntityMutations; |
| import org.apache.atlas.model.instance.EntityMutations.EntityOperation; |
| import org.apache.atlas.model.instance.GuidMapping; |
| import org.apache.atlas.services.MetadataService; |
| import org.apache.atlas.type.AtlasClassificationType; |
| import org.apache.atlas.type.AtlasEntityType; |
| import org.apache.atlas.type.AtlasType; |
| import org.apache.atlas.type.AtlasTypeRegistry; |
| import org.apache.atlas.typesystem.IReferenceableInstance; |
| import org.apache.atlas.typesystem.IStruct; |
| import org.apache.atlas.typesystem.ITypedReferenceableInstance; |
| import org.apache.atlas.typesystem.ITypedStruct; |
| 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.exception.TypeNotFoundException; |
| import org.apache.atlas.repository.converters.AtlasFormatConverter.ConverterContext; |
| import org.apache.atlas.typesystem.types.ValueConversionException; |
| import org.apache.commons.collections.CollectionUtils; |
| import org.apache.commons.collections.MapUtils; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| @Singleton |
| public class AtlasInstanceConverter { |
| |
| private static final Logger LOG = LoggerFactory.getLogger(AtlasInstanceConverter.class); |
| |
| @Inject |
| private AtlasTypeRegistry typeRegistry; |
| |
| @Inject |
| private AtlasFormatConverters instanceFormatters; |
| |
| @Inject |
| private MetadataService metadataService; |
| |
| public ITypedReferenceableInstance[] getITypedReferenceables(Collection<AtlasEntity> entities) throws AtlasBaseException { |
| ITypedReferenceableInstance[] entitiesInOldFormat = new ITypedReferenceableInstance[entities.size()]; |
| |
| AtlasFormatConverter.ConverterContext ctx = new AtlasFormatConverter.ConverterContext(); |
| for(Iterator<AtlasEntity> i = entities.iterator(); i.hasNext(); ) { |
| ctx.addEntity(i.next()); |
| } |
| |
| Iterator<AtlasEntity> entityIterator = entities.iterator(); |
| for (int i = 0; i < entities.size(); i++) { |
| ITypedReferenceableInstance typedInstance = getITypedReferenceable(entityIterator.next()); |
| entitiesInOldFormat[i] = typedInstance; |
| } |
| return entitiesInOldFormat; |
| } |
| |
| public ITypedReferenceableInstance getITypedReferenceable(AtlasEntity entity) throws AtlasBaseException { |
| try { |
| return metadataService.getEntityDefinition(entity.getGuid()); |
| } catch (AtlasException e) { |
| LOG.error("Exception while getting a typed reference for the entity ", e); |
| throw toAtlasBaseException(e); |
| } |
| } |
| |
| public ITypedReferenceableInstance getITypedReferenceable(String guid) throws AtlasBaseException { |
| try { |
| return metadataService.getEntityDefinition(guid); |
| } catch (AtlasException e) { |
| LOG.error("Exception while getting a typed reference for the entity ", e); |
| throw toAtlasBaseException(e); |
| } |
| } |
| |
| public Referenceable getReferenceable(AtlasEntity entity, final ConverterContext ctx) throws AtlasBaseException { |
| AtlasFormatConverter converter = instanceFormatters.getConverter(TypeCategory.ENTITY); |
| AtlasType entityType = typeRegistry.getType(entity.getTypeName()); |
| Referenceable ref = (Referenceable) converter.fromV2ToV1(entity, entityType, ctx); |
| |
| return ref; |
| } |
| |
| public ITypedStruct getTrait(AtlasClassification classification) throws AtlasBaseException { |
| AtlasFormatConverter converter = instanceFormatters.getConverter(TypeCategory.CLASSIFICATION); |
| AtlasType classificationType = typeRegistry.getType(classification.getTypeName()); |
| Struct trait = (Struct)converter.fromV2ToV1(classification, classificationType, new ConverterContext()); |
| |
| try { |
| return metadataService.createTraitInstance(trait); |
| } catch (AtlasException e) { |
| LOG.error("Exception while getting a typed reference for the entity ", e); |
| throw toAtlasBaseException(e); |
| } |
| } |
| |
| public AtlasClassification getClassification(IStruct classification) throws AtlasBaseException { |
| AtlasFormatConverter converter = instanceFormatters.getConverter(TypeCategory.CLASSIFICATION); |
| AtlasClassificationType classificationType = typeRegistry.getClassificationTypeByName(classification.getTypeName()); |
| if (classificationType == null) { |
| throw new AtlasBaseException(AtlasErrorCode.TYPE_NAME_INVALID, TypeCategory.CLASSIFICATION.name(), classification.getTypeName()); |
| } |
| AtlasClassification ret = (AtlasClassification)converter.fromV1ToV2(classification, classificationType, new AtlasFormatConverter.ConverterContext()); |
| |
| return ret; |
| } |
| |
| public AtlasEntitiesWithExtInfo toAtlasEntity(IReferenceableInstance referenceable) throws AtlasBaseException { |
| AtlasEntityFormatConverter converter = (AtlasEntityFormatConverter) instanceFormatters.getConverter(TypeCategory.ENTITY); |
| AtlasEntityType entityType = typeRegistry.getEntityTypeByName(referenceable.getTypeName()); |
| |
| if (entityType == null) { |
| throw new AtlasBaseException(AtlasErrorCode.TYPE_NAME_INVALID, TypeCategory.ENTITY.name(), referenceable.getTypeName()); |
| } |
| |
| // validate |
| try { |
| metadataService.validateAndConvertToTypedInstance(referenceable, entityType.getTypeName()); |
| } catch (AtlasException excp) { |
| throw toAtlasBaseException(excp); |
| } |
| |
| ConverterContext ctx = new ConverterContext(); |
| AtlasEntity entity = converter.fromV1ToV2(referenceable, entityType, ctx); |
| |
| ctx.addEntity(entity); |
| |
| return ctx.getEntities(); |
| } |
| |
| public static EntityMutationResponse toEntityMutationResponse(AtlasClient.EntityResult entityResult) { |
| |
| CreateUpdateEntitiesResult result = new CreateUpdateEntitiesResult(); |
| result.setEntityResult(entityResult); |
| return toEntityMutationResponse(result); |
| } |
| |
| public static EntityMutationResponse toEntityMutationResponse(CreateUpdateEntitiesResult result) { |
| EntityMutationResponse response = new EntityMutationResponse(); |
| for (String guid : result.getCreatedEntities()) { |
| AtlasEntityHeader header = new AtlasEntityHeader(); |
| header.setGuid(guid); |
| response.addEntity(EntityMutations.EntityOperation.CREATE, header); |
| } |
| |
| for (String guid : result.getUpdatedEntities()) { |
| AtlasEntityHeader header = new AtlasEntityHeader(); |
| header.setGuid(guid); |
| response.addEntity(EntityMutations.EntityOperation.UPDATE, header); |
| } |
| |
| for (String guid : result.getDeletedEntities()) { |
| AtlasEntityHeader header = new AtlasEntityHeader(); |
| header.setGuid(guid); |
| response.addEntity(EntityMutations.EntityOperation.DELETE, header); |
| } |
| GuidMapping guidMapping = result.getGuidMapping(); |
| if(guidMapping != null) { |
| response.setGuidAssignments(guidMapping.getGuidAssignments()); |
| } |
| return response; |
| } |
| |
| public static AtlasBaseException toAtlasBaseException(AtlasException e) { |
| if (e instanceof EntityExistsException) { |
| return new AtlasBaseException(AtlasErrorCode.INSTANCE_ALREADY_EXISTS, e.getMessage()); |
| } |
| |
| if ( e instanceof EntityNotFoundException || e instanceof TraitNotFoundException) { |
| return new AtlasBaseException(AtlasErrorCode.INSTANCE_NOT_FOUND, e.getMessage()); |
| } |
| |
| if ( e instanceof TypeNotFoundException) { |
| return new AtlasBaseException(AtlasErrorCode.TYPE_NAME_NOT_FOUND, e.getMessage()); |
| } |
| |
| if (e instanceof ValueConversionException) { |
| return new AtlasBaseException(AtlasErrorCode.INVALID_VALUE, e, e.getMessage()); |
| } |
| |
| return new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, e.getMessage()); |
| } |
| |
| |
| public AtlasEntity.AtlasEntitiesWithExtInfo toAtlasEntities(List<Referenceable> referenceables) throws AtlasBaseException { |
| if (LOG.isDebugEnabled()) { |
| LOG.debug("==> toAtlasEntities"); |
| } |
| |
| AtlasFormatConverter.ConverterContext context = new AtlasFormatConverter.ConverterContext(); |
| for (Referenceable referenceable : referenceables) { |
| AtlasEntity entity = fromV1toV2Entity(referenceable, context); |
| |
| context.addEntity(entity); |
| } |
| if (LOG.isDebugEnabled()) { |
| LOG.debug("<== toAtlasEntities"); |
| } |
| |
| return context.getEntities(); |
| } |
| |
| public AtlasEntitiesWithExtInfo toAtlasEntities(String entitiesJson) throws AtlasBaseException, AtlasException { |
| ITypedReferenceableInstance[] referenceables = metadataService.deserializeClassInstances(entitiesJson); |
| AtlasEntityFormatConverter converter = (AtlasEntityFormatConverter) instanceFormatters.getConverter(TypeCategory.ENTITY); |
| ConverterContext context = new ConverterContext(); |
| AtlasEntitiesWithExtInfo ret = null; |
| |
| if (referenceables != null) { |
| for (IReferenceableInstance referenceable : referenceables) { |
| AtlasEntityType entityType = typeRegistry.getEntityTypeByName(referenceable.getTypeName()); |
| |
| if (entityType == null) { |
| throw new AtlasBaseException(AtlasErrorCode.TYPE_NAME_INVALID, TypeCategory.ENTITY.name(), referenceable.getTypeName()); |
| } |
| |
| AtlasEntity entity = converter.fromV1ToV2(referenceable, entityType, context); |
| |
| context.addEntity(entity); |
| } |
| |
| ret = context.getEntities(); |
| } |
| |
| return ret; |
| } |
| |
| private AtlasEntity fromV1toV2Entity(Referenceable referenceable, AtlasFormatConverter.ConverterContext context) throws AtlasBaseException { |
| if (LOG.isDebugEnabled()) { |
| LOG.debug("==> fromV1toV2Entity"); |
| } |
| |
| AtlasEntityFormatConverter converter = (AtlasEntityFormatConverter) instanceFormatters.getConverter(TypeCategory.ENTITY); |
| |
| AtlasEntity entity = converter.fromV1ToV2(referenceable, typeRegistry.getType(referenceable.getTypeName()), context); |
| |
| if (LOG.isDebugEnabled()) { |
| LOG.debug("<== fromV1toV2Entity"); |
| } |
| return entity; |
| } |
| |
| public CreateUpdateEntitiesResult toCreateUpdateEntitiesResult(EntityMutationResponse reponse) { |
| CreateUpdateEntitiesResult ret = null; |
| |
| if (reponse != null) { |
| Map<EntityOperation, List<AtlasEntityHeader>> mutatedEntities = reponse.getMutatedEntities(); |
| Map<String, String> guidAssignments = reponse.getGuidAssignments(); |
| |
| ret = new CreateUpdateEntitiesResult(); |
| |
| if (MapUtils.isNotEmpty(guidAssignments)) { |
| ret.setGuidMapping(new GuidMapping(guidAssignments)); |
| } |
| |
| if (MapUtils.isNotEmpty(mutatedEntities)) { |
| EntityResult entityResult = new EntityResult(); |
| |
| for (Map.Entry<EntityOperation, List<AtlasEntityHeader>> e : mutatedEntities.entrySet()) { |
| switch (e.getKey()) { |
| case CREATE: |
| List<AtlasEntityHeader> createdEntities = mutatedEntities.get(EntityOperation.CREATE); |
| if (CollectionUtils.isNotEmpty(createdEntities)) { |
| Collections.reverse(createdEntities); |
| entityResult.set(EntityResult.OP_CREATED, getGuids(createdEntities)); |
| } |
| break; |
| case UPDATE: |
| List<AtlasEntityHeader> updatedEntities = mutatedEntities.get(EntityOperation.UPDATE); |
| if (CollectionUtils.isNotEmpty(updatedEntities)) { |
| Collections.reverse(updatedEntities); |
| entityResult.set(EntityResult.OP_UPDATED, getGuids(updatedEntities)); |
| } |
| break; |
| case PARTIAL_UPDATE: |
| List<AtlasEntityHeader> partialUpdatedEntities = mutatedEntities.get(EntityOperation.PARTIAL_UPDATE); |
| if (CollectionUtils.isNotEmpty(partialUpdatedEntities)) { |
| Collections.reverse(partialUpdatedEntities); |
| entityResult.set(EntityResult.OP_UPDATED, getGuids(partialUpdatedEntities)); |
| } |
| break; |
| case DELETE: |
| List<AtlasEntityHeader> deletedEntities = mutatedEntities.get(EntityOperation.DELETE); |
| if (CollectionUtils.isNotEmpty(deletedEntities)) { |
| Collections.reverse(deletedEntities); |
| entityResult.set(EntityResult.OP_DELETED, getGuids(deletedEntities)); |
| } |
| break; |
| } |
| |
| } |
| |
| ret.setEntityResult(entityResult); |
| } |
| } |
| |
| return ret; |
| } |
| |
| public List<String> getGuids(List<AtlasEntityHeader> entities) { |
| List<String> ret = null; |
| |
| if (CollectionUtils.isNotEmpty(entities)) { |
| ret = new ArrayList<>(); |
| for (AtlasEntityHeader entity : entities) { |
| ret.add(entity.getGuid()); |
| } |
| } |
| |
| return ret; |
| } |
| } |