| /** |
| * 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.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 ResourceProvider taxonomyResourceProvider; |
| private ResourceProvider entityResourceProvider; |
| private ResourceProvider entityTagResourceProvider; |
| |
| public TermResourceProvider(AtlasTypeSystem typeSystem) { |
| super(typeSystem, new TermResourceDefinition()); |
| } |
| |
| @Override |
| public Result getResourceById(Request request) throws ResourceNotFoundException { |
| //todo: shouldn't need to add this here |
| request.getQueryProperties().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.getQueryProperties(), 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.getQueryProperties().remove("termPath"); |
| String qualifiedTermName = termPath.getFullyQualifiedName(); |
| request.getQueryProperties().put("name", qualifiedTermName); |
| resourceDefinition.validateCreatePayload(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.getQueryProperties()); |
| 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.getQueryProperties()); |
| } |
| |
| @Override |
| public Collection<String> createResources(Request request) throws InvalidQueryException, ResourceNotFoundException { |
| throw new UnsupportedOperationException("Creating multiple Terms in a request is not currently supported"); |
| } |
| |
| @Override |
| public void updateResourceById(Request request) throws ResourceNotFoundException, InvalidPayloadException { |
| resourceDefinition.validateUpdatePayload(request); |
| String termName = request.<TermPath>getProperty("termPath").getFullyQualifiedName(); |
| request.getQueryProperties().put("name", termName); |
| AtlasQuery atlasQuery; |
| try { |
| atlasQuery = queryFactory.createTermQuery(request); |
| } catch (InvalidQueryException e) { |
| throw new CatalogRuntimeException("Unable to compile internal Term query: " + e, e); |
| } |
| Map<String, Object> updateProperties = request.getUpdateProperties(); |
| Collection<Map<String, Object>> results = atlasQuery.execute(updateProperties); |
| if (results.isEmpty()) { |
| throw new ResourceNotFoundException(String.format("Term '%s' not found.", |
| termName)); |
| } |
| // only the term 'description' property is set on entity tags |
| if (updateProperties.containsKey("description")) { |
| // 'description' property is being updated so we need to update tags |
| String tagQueryString = String.format("name:%s", termName); |
| Request tagRequest = new CollectionRequest( |
| Collections.<String, Object>singletonMap("id", "*"), tagQueryString, null); |
| AtlasQuery tagQuery; |
| try { |
| tagQuery = queryFactory.createEntityTagQuery(tagRequest); |
| } catch (InvalidQueryException e) { |
| throw new CatalogRuntimeException("Unable to compile internal Entity Tag query: " + e, e); |
| } |
| tagQuery.execute(Collections.singletonMap("description", updateProperties.get("description"))); |
| } |
| } |
| |
| @Override |
| public void deleteResourceById(Request request) throws ResourceNotFoundException, InvalidPayloadException { |
| // will result in expected ResourceNotFoundException if term doesn't exist |
| getResourceById(request); |
| |
| TermPath termPath = (TermPath) request.getQueryProperties().get("termPath"); |
| String taxonomyId = getTaxonomyId(termPath); |
| deleteChildren(taxonomyId, termPath); |
| deleteTerm(taxonomyId, termPath); |
| } |
| |
| protected void deleteChildren(String taxonomyId, TermPath termPath) |
| throws ResourceNotFoundException, InvalidPayloadException { |
| |
| TermPath collectionTermPath = new TermPath(termPath.getFullyQualifiedName() + "."); |
| Request queryRequest = new CollectionRequest(Collections.<String, Object>singletonMap("termPath", |
| collectionTermPath), null); |
| |
| AtlasQuery collectionQuery; |
| try { |
| collectionQuery = queryFactory.createTermQuery(queryRequest); |
| } catch (InvalidQueryException e) { |
| throw new CatalogRuntimeException("Failed to compile internal predicate: " + e, e); |
| } |
| |
| Collection<Map<String, Object>> children = collectionQuery.execute(); |
| for (Map<String, Object> childMap : children) { |
| deleteTerm(taxonomyId, new TermPath(String.valueOf(childMap.get("name")))); |
| } |
| } |
| |
| private void deleteTerm(String taxonomyId, TermPath termPath) |
| throws ResourceNotFoundException, InvalidPayloadException { |
| |
| String fullyQualifiedName = termPath.getFullyQualifiedName(); |
| deleteEntityTagsForTerm(fullyQualifiedName); |
| |
| // delete term instance associated with the taxonomy |
| typeSystem.deleteTag(taxonomyId, fullyQualifiedName); |
| //todo: Currently no way to delete type via MetadataService or MetadataRepository |
| } |
| |
| private void deleteEntityTagsForTerm(String fullyQualifiedName) throws ResourceNotFoundException { |
| String entityQueryStr = String.format("tags/name:%s", fullyQualifiedName); |
| Request entityRequest = new CollectionRequest(Collections.<String, Object>emptyMap(), entityQueryStr); |
| Result entityResult; |
| try { |
| entityResult = getEntityResourceProvider().getResources(entityRequest); |
| } catch (InvalidQueryException e) { |
| throw new CatalogRuntimeException(String.format( |
| "Failed to compile internal predicate for query '%s': %s", entityQueryStr, e), e); |
| } |
| |
| for (Map<String, Object> entityResultMap : entityResult.getPropertyMaps()) { |
| Map<String, Object> tagRequestProperties = new HashMap<>(); |
| tagRequestProperties.put("id", String.valueOf(entityResultMap.get("id"))); |
| tagRequestProperties.put("name", fullyQualifiedName); |
| try { |
| getEntityTagResourceProvider().deleteResourceById(new InstanceRequest(tagRequestProperties)); |
| } catch (InvalidPayloadException e) { |
| throw new CatalogRuntimeException( |
| "An internal error occurred while trying to delete an entity tag: " + e, e); |
| } |
| } |
| } |
| |
| private String getTaxonomyId(TermPath termPath) throws ResourceNotFoundException { |
| Request taxonomyRequest = new InstanceRequest(Collections.<String, Object>singletonMap( |
| "name", termPath.getTaxonomyName())); |
| taxonomyRequest.addAdditionalSelectProperties(Collections.singleton("id")); |
| // will result in proper ResourceNotFoundException if taxonomy doesn't exist |
| Result taxonomyResult = getTaxonomyResourceProvider().getResourceById(taxonomyRequest); |
| |
| Map<String, Object> taxonomyResultMap = taxonomyResult.getPropertyMaps().iterator().next(); |
| return String.valueOf(taxonomyResultMap.get("id")); |
| } |
| |
| //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; |
| } |
| |
| protected synchronized ResourceProvider getEntityResourceProvider() { |
| if (entityResourceProvider == null) { |
| entityResourceProvider = new EntityResourceProvider(typeSystem); |
| } |
| return entityResourceProvider; |
| } |
| |
| protected synchronized ResourceProvider getEntityTagResourceProvider() { |
| if (entityTagResourceProvider == null) { |
| entityTagResourceProvider = new EntityTagResourceProvider(typeSystem); |
| } |
| return entityTagResourceProvider; |
| } |
| } |
| |
| |
| |
| |
| |
| |
| |