/** * 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.web.resources; import org.apache.atlas.AtlasException; import org.apache.atlas.catalog.*; import org.apache.atlas.catalog.exception.CatalogException; import org.apache.atlas.catalog.exception.InvalidPayloadException; import org.apache.atlas.exception.AtlasBaseException; import org.apache.atlas.services.MetadataService; import org.apache.atlas.store.AtlasTypeDefStore; import org.apache.atlas.utils.AtlasPerfTracer; import org.apache.atlas.web.util.Servlets; import org.slf4j.Logger; import javax.inject.Inject; import javax.inject.Singleton; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.PathSegment; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Service which handles API requests for taxonomy and term resources. */ @Path("v1/taxonomies") @Singleton public class TaxonomyService extends BaseService { private static final Logger PERF_LOG = AtlasPerfTracer.getPerfLogger("rest.TaxonomyService"); private ResourceProvider taxonomyResourceProvider; private ResourceProvider termResourceProvider; @Inject public void setMetadataService(MetadataService metadataService, AtlasTypeDefStore typeDefStore) throws AtlasBaseException { DefaultTypeSystem typeSystem = new DefaultTypeSystem(metadataService, typeDefStore); taxonomyResourceProvider = createTaxonomyResourceProvider(typeSystem); termResourceProvider = createTermResourceProvider(typeSystem); } @GET @Path("{taxonomyName}") @Produces(Servlets.JSON_MEDIA_TYPE) public Response getTaxonomy(@Context HttpHeaders headers, @Context UriInfo ui, @PathParam("taxonomyName") String taxonomyName) throws CatalogException { AtlasPerfTracer perf = null; try { if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) { perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "TaxonomyService.getTaxonomy(" + taxonomyName + ")"); } Map<String, Object> properties = new HashMap<>(); properties.put("name", taxonomyName); Result result = getResource(taxonomyResourceProvider, new InstanceRequest(properties)); return Response.status(Response.Status.OK).entity(getSerializer().serialize(result, ui)).build(); } finally { AtlasPerfTracer.log(perf); } } @GET @Produces(Servlets.JSON_MEDIA_TYPE) public Response getTaxonomies(@Context HttpHeaders headers, @Context UriInfo ui) throws CatalogException { AtlasPerfTracer perf = null; try { if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) { perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "TaxonomyService.getTaxonomies()"); } String queryString = decode(getQueryString(ui)); Request request = new CollectionRequest(Collections.<String, Object>emptyMap(), queryString); Result result = getResources(taxonomyResourceProvider, request); return Response.status(Response.Status.OK).entity(getSerializer().serialize(result, ui)).build(); } finally { AtlasPerfTracer.log(perf); } } @POST @Path("{taxonomyName}") @Produces(Servlets.JSON_MEDIA_TYPE) public Response createTaxonomy(String body, @Context HttpHeaders headers, @Context UriInfo ui, @PathParam("taxonomyName") String taxonomyName) throws CatalogException { AtlasPerfTracer perf = null; try { if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) { perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "TaxonomyService.createTaxonomy(" + taxonomyName + ")"); } Map<String, Object> properties = parsePayload(body); properties.put("name", taxonomyName); createResource(taxonomyResourceProvider, new InstanceRequest(properties)); return Response.status(Response.Status.CREATED).entity( new Results(ui.getRequestUri().toString(), 201)).build(); } finally { AtlasPerfTracer.log(perf); } } @PUT @Path("{taxonomyName}") @Produces(Servlets.JSON_MEDIA_TYPE) public Response updateTaxonomy(String body, @Context HttpHeaders headers, @Context UriInfo ui, @PathParam("taxonomyName") String taxonomyName) throws CatalogException { AtlasPerfTracer perf = null; try { if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) { perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "TaxonomyService.updateTaxonomy(" + taxonomyName + ")"); } Map<String, Object> queryProperties = new HashMap<>(); queryProperties.put("name", taxonomyName); Map<String, Object> updateProperties = parsePayload(body); updateResource(taxonomyResourceProvider, new InstanceRequest(queryProperties, updateProperties)); return Response.status(Response.Status.OK).entity( new Results(ui.getRequestUri().toString(), 200)).build(); } finally { AtlasPerfTracer.log(perf); } } @DELETE @Path("{taxonomyName}") @Produces(Servlets.JSON_MEDIA_TYPE) public Response deleteTaxonomy(@Context HttpHeaders headers, @Context UriInfo ui, @PathParam("taxonomyName") String taxonomyName) throws CatalogException { AtlasPerfTracer perf = null; try { if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) { perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "TaxonomyService.deleteTaxonomy(" + taxonomyName + ")"); } Map<String, Object> properties = new HashMap<>(); properties.put("name", taxonomyName); deleteResource(taxonomyResourceProvider, new InstanceRequest(properties)); return Response.status(Response.Status.OK).entity( new Results(ui.getRequestUri().toString(), 200)).build(); } finally { AtlasPerfTracer.log(perf); } } @GET @Path("{taxonomyName}/terms/{termName}") @Produces(Servlets.JSON_MEDIA_TYPE) public Response getTaxonomyTerm(@Context HttpHeaders headers, @Context UriInfo ui, @PathParam("taxonomyName") String taxonomyName, @PathParam("termName") String termName) throws CatalogException { AtlasPerfTracer perf = null; try { if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) { perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "TaxonomyService.getTaxonomyTerm(" + taxonomyName + ", " + termName + ")"); } TermPath termPath = new TermPath(taxonomyName, termName); Map<String, Object> properties = new HashMap<>(); properties.put("termPath", termPath); Result result = getResource(termResourceProvider, new InstanceRequest(properties)); return Response.status(Response.Status.OK).entity(getSerializer().serialize(result, ui)).build(); } finally { AtlasPerfTracer.log(perf); } } @GET @Path("{taxonomyName}/terms") @Produces(Servlets.JSON_MEDIA_TYPE) public Response getTaxonomyTerms(@Context HttpHeaders headers, @Context UriInfo ui, @PathParam("taxonomyName") String taxonomyName) throws CatalogException { AtlasPerfTracer perf = null; try { if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) { perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "TaxonomyService.getTaxonomyTerms(" + taxonomyName + ")"); } String queryString = decode(getQueryString(ui)); TermPath termPath = new TermPath(taxonomyName, null); Request request = new CollectionRequest( Collections.<String, Object>singletonMap("termPath", termPath), queryString); Result result = getResources(termResourceProvider, request); return Response.status(Response.Status.OK).entity(getSerializer().serialize(result, ui)).build(); } finally { AtlasPerfTracer.log(perf); } } @GET @Path("{taxonomyName}/terms/{rootTerm}/{remainder:.*}") @Produces(Servlets.JSON_MEDIA_TYPE) public Response getSubTerms(@Context HttpHeaders headers, @Context UriInfo ui, @PathParam("taxonomyName") String taxonomyName, @PathParam("rootTerm") String rootTerm, @PathParam("remainder") String remainder) throws CatalogException { AtlasPerfTracer perf = null; try { if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) { perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "TaxonomyService.getSubTerms(" + taxonomyName + ", " + rootTerm + ", " + remainder + ")"); } Result result; String termName = String.format("%s%s", rootTerm, remainder.replaceAll("/?terms/?([.]*)", "$1.")); String queryString = decode(getQueryString(ui)); TermPath termPath = new TermPath(taxonomyName, termName); Map<String, Object> properties = new HashMap<>(); properties.put("termPath", termPath); List<PathSegment> pathSegments = ui.getPathSegments(); int lastIndex = pathSegments.size() - 1; String lastSegment = pathSegments.get(lastIndex).getPath(); if (lastSegment.equals("terms") || (lastSegment.isEmpty() && pathSegments.get(lastIndex - 1).getPath().equals("terms"))) { result = getResources(termResourceProvider, new CollectionRequest(properties, queryString)); } else { result = getResource(termResourceProvider, new InstanceRequest(properties)); } return Response.status(Response.Status.OK).entity(getSerializer().serialize(result, ui)).build(); } finally { AtlasPerfTracer.log(perf); } } @POST @Path("{taxonomyName}/terms/{termName}") @Produces(Servlets.JSON_MEDIA_TYPE) public Response createTerm(String body, @Context HttpHeaders headers, @Context UriInfo ui, @PathParam("taxonomyName") String taxonomyName, @PathParam("termName") String termName) throws CatalogException { AtlasPerfTracer perf = null; try { if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) { perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "TaxonomyService.createTerm(" + taxonomyName + ", " + termName + ")"); } Map<String, Object> properties = parsePayload(body); validateName(termName); properties.put("termPath", new TermPath(taxonomyName, termName)); createResource(termResourceProvider, new InstanceRequest(properties)); return Response.status(Response.Status.CREATED).entity( new Results(ui.getRequestUri().toString(), 201)).build(); } finally { AtlasPerfTracer.log(perf); } } @POST @Path("{taxonomyName}/terms/{termName}/{remainder:.*}") @Produces(Servlets.JSON_MEDIA_TYPE) public Response createSubTerm(String body, @Context HttpHeaders headers, @Context UriInfo ui, @PathParam("taxonomyName") String taxonomyName, @PathParam("termName") String termName, @PathParam("remainder") String remainder) throws CatalogException { AtlasPerfTracer perf = null; try { if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) { perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "TaxonomyService.createSubTerm(" + taxonomyName + ", " + termName + ", " + remainder + ")"); } Map<String, Object> properties = parsePayload(body); String[] pathTokens = remainder.split("/"); validateName(pathTokens[pathTokens.length - 1]); properties.put("termPath", new TermPath(taxonomyName, String.format("%s%s", termName, remainder.replaceAll("/?terms/?([.]*)", "$1.")))); createResource(termResourceProvider, new InstanceRequest(properties)); return Response.status(Response.Status.CREATED).entity( new Results(ui.getRequestUri().toString(), 201)).build(); } finally { AtlasPerfTracer.log(perf); } } @PUT @Path("{taxonomyName}/terms/{termName}") @Produces(Servlets.JSON_MEDIA_TYPE) public Response updateTerm(String body, @Context HttpHeaders headers, @Context UriInfo ui, @PathParam("taxonomyName") String taxonomyName, @PathParam("termName") String termName) throws CatalogException { AtlasPerfTracer perf = null; try { if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) { perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "TaxonomyService.updateTerm(" + taxonomyName + ", " + termName + ")"); } Map<String, Object> queryProperties = new HashMap<>(); queryProperties.put("termPath", new TermPath(taxonomyName, termName)); Map<String, Object> updateProperties = parsePayload(body); updateResource(termResourceProvider, new InstanceRequest(queryProperties, updateProperties)); return Response.status(Response.Status.OK).entity( new Results(ui.getRequestUri().toString(), 200)).build(); } finally { AtlasPerfTracer.log(perf); } } @PUT @Path("{taxonomyName}/terms/{termName}/{remainder:.*}") @Produces(Servlets.JSON_MEDIA_TYPE) public Response updateSubTerm(String body, @Context HttpHeaders headers, @Context UriInfo ui, @PathParam("taxonomyName") String taxonomyName, @PathParam("termName") String termName, @PathParam("remainder") String remainder) throws CatalogException { AtlasPerfTracer perf = null; try { if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) { perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "TaxonomyService.updateSubTerm(" + taxonomyName + ", " + termName + ", " + remainder + ")"); } Map<String, Object> queryProperties = new HashMap<>(); queryProperties.put("termPath", new TermPath(taxonomyName, String.format("%s%s", termName, remainder.replaceAll("/?terms/?([.]*)", "$1.")))); Map<String, Object> updateProperties = parsePayload(body); updateResource(termResourceProvider, new InstanceRequest(queryProperties, updateProperties)); return Response.status(Response.Status.OK).entity( new Results(ui.getRequestUri().toString(), 200)).build(); } finally { AtlasPerfTracer.log(perf); } } @DELETE @Path("{taxonomyName}/terms/{termName}") @Produces(Servlets.JSON_MEDIA_TYPE) public Response deleteTerm(@Context HttpHeaders headers, @Context UriInfo ui, @PathParam("taxonomyName") String taxonomyName, @PathParam("termName") String termName) throws CatalogException { AtlasPerfTracer perf = null; try { if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) { perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "TaxonomyService.deleteTerm(" + taxonomyName + ", " + termName + ")"); } Map<String, Object> properties = new HashMap<>(); properties.put("termPath", new TermPath(taxonomyName, termName)); deleteResource(termResourceProvider, new InstanceRequest(properties)); return Response.status(Response.Status.OK).entity( new Results(ui.getRequestUri().toString(), 200)).build(); } finally { AtlasPerfTracer.log(perf); } } @DELETE @Path("{taxonomyName}/terms/{termName}/{remainder:.*}") @Produces(Servlets.JSON_MEDIA_TYPE) public Response deleteSubTerm(@Context HttpHeaders headers, @Context UriInfo ui, @PathParam("taxonomyName") String taxonomyName, @PathParam("termName") String termName, @PathParam("remainder") String remainder) throws CatalogException { AtlasPerfTracer perf = null; try { if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) { perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "TaxonomyService.deleteSubTerm(" + taxonomyName + ", " + termName + ", " + remainder + ")"); } Map<String, Object> properties = new HashMap<>(); properties.put("termPath", new TermPath(taxonomyName, String.format("%s%s", termName, remainder.replaceAll("/?terms/?([.]*)", "$1.")))); deleteResource(termResourceProvider, new InstanceRequest(properties)); return Response.status(Response.Status.OK).entity( new Results(ui.getRequestUri().toString(), 200)).build(); } finally { AtlasPerfTracer.log(perf); } } protected ResourceProvider createTaxonomyResourceProvider(AtlasTypeSystem typeSystem) { return new TaxonomyResourceProvider(typeSystem); } protected ResourceProvider createTermResourceProvider(AtlasTypeSystem typeSystem) { return new TermResourceProvider(typeSystem); } private void validateName(String name) throws InvalidPayloadException { if (name.contains(".")) { throw new InvalidPayloadException("The \"name\" property may not contain the character '.'"); } } }