/*
* Copyright © 2015-2016 Cask Data, Inc.
*
* Licensed 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 co.cask.cdap.metadata;
import co.cask.cdap.common.BadRequestException;
import co.cask.cdap.common.NotFoundException;
import co.cask.cdap.common.conf.Constants;
import co.cask.cdap.proto.Id;
import co.cask.cdap.proto.ProgramType;
import co.cask.cdap.proto.codec.NamespacedIdCodec;
import co.cask.cdap.proto.metadata.MetadataRecord;
import co.cask.cdap.proto.metadata.MetadataScope;
import co.cask.cdap.proto.metadata.MetadataSearchResultRecord;
import co.cask.cdap.proto.metadata.MetadataSearchTargetType;
import co.cask.http.AbstractHttpHandler;
import co.cask.http.HttpResponder;
import com.google.common.base.Charsets;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.google.inject.Inject;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBufferInputStream;
import org.jboss.netty.handler.codec.http.HttpRequest;
import org.jboss.netty.handler.codec.http.HttpResponseStatus;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.Type;
import java.net.URLDecoder;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
/**
* HttpHandler for Metadata
*/
@Path(Constants.Gateway.API_VERSION_3)
public class MetadataHttpHandler extends AbstractHttpHandler {
private static final Gson GSON = new GsonBuilder()
.registerTypeAdapter(Id.NamespacedId.class, new NamespacedIdCodec())
.create();
private static final Type MAP_STRING_STRING_TYPE = new TypeToken<Map<String, String>>() { }.getType();
private static final Type LIST_STRING_TYPE = new TypeToken<List<String>>() { }.getType();
private static final Type SET_METADATA_RECORD_TYPE = new TypeToken<Set<MetadataRecord>>() { }.getType();
private static final Type SET_METADATA_SEARCH_RESULT_TYPE =
new TypeToken<Set<MetadataSearchResultRecord>>() { }.getType();
private static final Function<String, MetadataSearchTargetType> STRING_TO_TARGET_TYPE =
new Function<String, MetadataSearchTargetType>() {
@Override
public MetadataSearchTargetType apply(String input) {
return MetadataSearchTargetType.valueOf(input.toUpperCase());
}
};
private final MetadataAdmin metadataAdmin;
@Inject
MetadataHttpHandler(MetadataAdmin metadataAdmin) {
this.metadataAdmin = metadataAdmin;
}
@GET
@Path("/namespaces/{namespace-id}/apps/{app-id}/metadata")
public void getAppMetadata(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("app-id") String appId,
@QueryParam("scope") String scope) throws NotFoundException, BadRequestException {
Id.Application app = Id.Application.from(namespaceId, appId);
responder.sendJson(HttpResponseStatus.OK, getMetadata(app, scope), SET_METADATA_RECORD_TYPE, GSON);
}
@GET
@Path("/namespaces/{namespace-id}/apps/{app-id}/{program-type}/{program-id}/metadata")
public void getProgramMetadata(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("app-id") String appId,
@PathParam("program-type") String programType,
@PathParam("program-id") String programId,
@QueryParam("scope") String scope) throws NotFoundException, BadRequestException {
Id.Program program = Id.Program.from(Id.Application.from(namespaceId, appId),
ProgramType.valueOfCategoryName(programType), programId);
responder.sendJson(HttpResponseStatus.OK, getMetadata(program, scope), SET_METADATA_RECORD_TYPE, GSON);
}
@GET
@Path("/namespaces/{namespace-id}/artifacts/{artifact-name}/versions/{artifact-version}/metadata")
public void getArtifactMetadata(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("artifact-name") String artifactName,
@PathParam("artifact-version") String artifactVersionStr,
@QueryParam("scope") String scope) throws NotFoundException, BadRequestException {
Id.Artifact artifactId = Id.Artifact.from(Id.Namespace.from(namespaceId), artifactName, artifactVersionStr);
responder.sendJson(HttpResponseStatus.OK, getMetadata(artifactId, scope), SET_METADATA_RECORD_TYPE, GSON);
}
@GET
@Path("/namespaces/{namespace-id}/datasets/{dataset-id}/metadata")
public void getDatasetMetadata(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("dataset-id") String datasetId,
@QueryParam("scope") String scope) throws NotFoundException, BadRequestException {
Id.DatasetInstance datasetInstance = Id.DatasetInstance.from(namespaceId, datasetId);
responder.sendJson(HttpResponseStatus.OK, getMetadata(datasetInstance, scope), SET_METADATA_RECORD_TYPE, GSON);
}
@GET
@Path("/namespaces/{namespace-id}/streams/{stream-id}/metadata")
public void getStreamMetadata(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("stream-id") String streamId,
@QueryParam("scope") String scope) throws NotFoundException, BadRequestException {
Id.Stream stream = Id.Stream.from(namespaceId, streamId);
responder.sendJson(HttpResponseStatus.OK, getMetadata(stream, scope), SET_METADATA_RECORD_TYPE, GSON);
}
@GET
@Path("/namespaces/{namespace-id}/streams/{stream-id}/views/{view-id}/metadata")
public void getViewMetadata(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("stream-id") String streamId,
@PathParam("view-id") String viewId,
@QueryParam("scope") String scope) throws NotFoundException, BadRequestException {
Id.Stream.View view = Id.Stream.View.from(namespaceId, streamId, viewId);
responder.sendJson(HttpResponseStatus.OK, getMetadata(view, scope), SET_METADATA_RECORD_TYPE, GSON);
}
@GET
@Path("/namespaces/{namespace-id}/apps/{app-id}/metadata/properties")
public void getAppProperties(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("app-id") String appId,
@QueryParam("scope") String scope) throws NotFoundException, BadRequestException {
Id.Application app = Id.Application.from(namespaceId, appId);
responder.sendJson(HttpResponseStatus.OK, getProperties(app, scope));
}
@GET
@Path("/namespaces/{namespace-id}/artifacts/{artifact-name}/versions/{artifact-version}/metadata/properties")
public void getArtifactProperties(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("artifact-name") String artifactName,
@PathParam("artifact-version") String artifactVersionStr,
@QueryParam("scope") String scope) throws NotFoundException, BadRequestException {
Id.Artifact artifactId = Id.Artifact.from(Id.Namespace.from(namespaceId), artifactName, artifactVersionStr);
responder.sendJson(HttpResponseStatus.OK, getProperties(artifactId, scope));
}
@GET
@Path("/namespaces/{namespace-id}/apps/{app-id}/{program-type}/{program-id}/metadata/properties")
public void getProgramProperties(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("app-id") String appId,
@PathParam("program-type") String programType,
@PathParam("program-id") String programId,
@QueryParam("scope") String scope) throws NotFoundException, BadRequestException {
Id.Program program = Id.Program.from(Id.Application.from(namespaceId, appId),
ProgramType.valueOfCategoryName(programType), programId);
responder.sendJson(HttpResponseStatus.OK, getProperties(program, scope));
}
@GET
@Path("/namespaces/{namespace-id}/datasets/{dataset-id}/metadata/properties")
public void getDatasetProperties(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("dataset-id") String datasetId,
@QueryParam("scope") String scope) throws NotFoundException, BadRequestException {
Id.DatasetInstance datasetInstance = Id.DatasetInstance.from(namespaceId, datasetId);
responder.sendJson(HttpResponseStatus.OK, getProperties(datasetInstance, scope));
}
@GET
@Path("/namespaces/{namespace-id}/streams/{stream-id}/metadata/properties")
public void getStreamProperties(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("stream-id") String streamId,
@QueryParam("scope") String scope) throws NotFoundException, BadRequestException {
Id.Stream stream = Id.Stream.from(namespaceId, streamId);
responder.sendJson(HttpResponseStatus.OK, getProperties(stream, scope));
}
@GET
@Path("/namespaces/{namespace-id}/streams/{stream-id}/views/{view-id}/metadata/properties")
public void getViewProperties(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("stream-id") String streamId,
@PathParam("view-id") String viewId,
@QueryParam("scope") String scope) throws NotFoundException, BadRequestException {
Id.Stream.View view = Id.Stream.View.from(namespaceId, streamId, viewId);
responder.sendJson(HttpResponseStatus.OK, getProperties(view, scope));
}
@POST
@Path("/namespaces/{namespace-id}/apps/{app-id}/metadata/properties")
public void addAppProperties(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("app-id") String appId) throws BadRequestException, NotFoundException {
Id.Application app = Id.Application.from(namespaceId, appId);
metadataAdmin.addProperties(app, readMetadata(request));
responder.sendString(HttpResponseStatus.OK, "Metadata added successfully to " + app);
}
@POST
@Path("/namespaces/{namespace-id}/artifacts/{artifact-name}/versions/{artifact-version}/metadata/properties")
public void addArtifactProperties(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("artifact-name") String artifactName,
@PathParam("artifact-version") String artifactVersionStr)
throws BadRequestException, NotFoundException {
Id.Artifact artifactId = Id.Artifact.from(Id.Namespace.from(namespaceId), artifactName, artifactVersionStr);
metadataAdmin.addProperties(artifactId, readMetadata(request));
responder.sendString(HttpResponseStatus.OK, "Metadata added successfully to " + artifactId);
}
@POST
@Path("/namespaces/{namespace-id}/apps/{app-id}/{program-type}/{program-id}/metadata/properties")
public void addProgramProperties(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("app-id") String appId,
@PathParam("program-type") String programType,
@PathParam("program-id") String programId)
throws BadRequestException, NotFoundException {
Id.Program program = Id.Program.from(Id.Application.from(namespaceId, appId),
ProgramType.valueOfCategoryName(programType), programId);
metadataAdmin.addProperties(program, readMetadata(request));
responder.sendString(HttpResponseStatus.OK, "Metadata added successfully to " + program);
}
@POST
@Path("/namespaces/{namespace-id}/datasets/{dataset-id}/metadata/properties")
public void addDatasetProperties(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("dataset-id") String datasetId)
throws BadRequestException, NotFoundException {
Id.DatasetInstance dataset = Id.DatasetInstance.from(namespaceId, datasetId);
metadataAdmin.addProperties(dataset, readMetadata(request));
responder.sendString(HttpResponseStatus.OK, "Metadata added successfully to " + dataset);
}
@POST
@Path("/namespaces/{namespace-id}/streams/{stream-id}/metadata/properties")
public void addStreamProperties(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("stream-id") String streamId)
throws BadRequestException, NotFoundException {
Id.Stream stream = Id.Stream.from(namespaceId, streamId);
metadataAdmin.addProperties(stream, readMetadata(request));
responder.sendString(HttpResponseStatus.OK, "Metadata added successfully to " + stream);
}
@POST
@Path("/namespaces/{namespace-id}/streams/{stream-id}/views/{view-id}/metadata/properties")
public void addViewProperties(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("stream-id") String streamId,
@PathParam("view-id") String viewId) throws NotFoundException, BadRequestException {
Id.Stream.View view = Id.Stream.View.from(namespaceId, streamId, viewId);
metadataAdmin.addProperties(view, readMetadata(request));
responder.sendString(HttpResponseStatus.OK, "Metadata added successfully to " + view);
}
@DELETE
@Path("/namespaces/{namespace-id}/apps/{app-id}/metadata")
public void removeAppMetadata(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("app-id") String appId) throws NotFoundException {
Id.Application app = Id.Application.from(namespaceId, appId);
metadataAdmin.removeMetadata(app);
responder.sendString(HttpResponseStatus.OK,
String.format("Metadata for app %s deleted successfully.", app));
}
@DELETE
@Path("/namespaces/{namespace-id}/artifacts/{artifact-name}/versions/{artifact-version}/metadata")
public void removeArtifactMetadata(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("artifact-name") String artifactName,
@PathParam("artifact-version") String artifactVersionStr) throws NotFoundException {
Id.Artifact artifactId = Id.Artifact.from(Id.Namespace.from(namespaceId), artifactName, artifactVersionStr);
metadataAdmin.removeMetadata(artifactId);
responder.sendJson(HttpResponseStatus.OK,
String.format("Metadata for artifact %s deleted successfully.", artifactId));
}
@DELETE
@Path("/namespaces/{namespace-id}/apps/{app-id}/{program-type}/{program-id}/metadata")
public void removeProgramMetadata(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("app-id") String appId,
@PathParam("program-type") String programType,
@PathParam("program-id") String programId) throws NotFoundException {
Id.Program program = Id.Program.from(Id.Application.from(namespaceId, appId),
ProgramType.valueOfCategoryName(programType), programId);
metadataAdmin.removeMetadata(program);
responder.sendString(HttpResponseStatus.OK,
String.format("Metadata for program %s deleted successfully.", program));
}
@DELETE
@Path("/namespaces/{namespace-id}/datasets/{dataset-id}/metadata")
public void removeDatasetMetadata(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("dataset-id") String datasetId) throws NotFoundException {
Id.DatasetInstance dataset = Id.DatasetInstance.from(namespaceId, datasetId);
metadataAdmin.removeMetadata(dataset);
responder.sendString(HttpResponseStatus.OK,
String.format("Metadata for dataset %s deleted successfully.", dataset));
}
@DELETE
@Path("/namespaces/{namespace-id}/streams/{stream-id}/metadata")
public void removeStreamMetadata(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("stream-id") String streamId) throws NotFoundException {
Id.Stream stream = Id.Stream.from(namespaceId, streamId);
metadataAdmin.removeMetadata(stream);
responder.sendString(HttpResponseStatus.OK,
String.format("Metadata for stream %s deleted successfully.", stream));
}
@DELETE
@Path("/namespaces/{namespace-id}/streams/{stream-id}/views/{view-id}/metadata")
public void removeViewMetadata(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("stream-id") String streamId,
@PathParam("view-id") String viewId) throws NotFoundException {
Id.Stream.View view = Id.Stream.View.from(namespaceId, streamId, viewId);
metadataAdmin.removeMetadata(view);
responder.sendString(HttpResponseStatus.OK,
String.format("Metadata for view %s deleted successfully.", view));
}
@DELETE
@Path("/namespaces/{namespace-id}/apps/{app-id}/metadata/properties")
public void removeAppProperties(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("app-id") String appId) throws NotFoundException {
Id.Application app = Id.Application.from(namespaceId, appId);
metadataAdmin.removeProperties(app);
responder.sendString(HttpResponseStatus.OK,
String.format("Metadata properties for app %s deleted successfully.", app));
}
@DELETE
@Path("/namespaces/{namespace-id}/apps/{app-id}/metadata/properties/{property}")
public void removeAppProperty(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("app-id") String appId,
@PathParam("property") String property) throws NotFoundException {
Id.Application app = Id.Application.from(namespaceId, appId);
metadataAdmin.removeProperties(app, property);
responder.sendString(HttpResponseStatus.OK,
String.format("Metadata property %s for app %s deleted successfully.", property, app));
}
@DELETE
@Path("/namespaces/{namespace-id}/artifacts/{artifact-name}/versions/{artifact-version}/metadata/properties")
public void removeArtifactProperties(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("artifact-name") String artifactName,
@PathParam("artifact-version") String artifactVersionStr)
throws NotFoundException {
Id.Artifact artifactId = Id.Artifact.from(Id.Namespace.from(namespaceId), artifactName, artifactVersionStr);
metadataAdmin.removeProperties(artifactId);
responder.sendJson(HttpResponseStatus.OK,
String.format("Metadata properties for artifact %s deleted successfully.", artifactId));
}
@DELETE
@Path("/namespaces/{namespace-id}/artifacts/{artifact-name}/versions/{artifact-version}/" +
"metadata/properties/{property}")
public void removeArtifactProperty(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("artifact-name") String artifactName,
@PathParam("artifact-version") String artifactVersionStr,
@PathParam("property") String property) throws NotFoundException {
Id.Artifact artifactId = Id.Artifact.from(Id.Namespace.from(namespaceId), artifactName, artifactVersionStr);
metadataAdmin.removeProperties(artifactId, property);
responder.sendJson(HttpResponseStatus.OK,
String.format("Metadata property %s for artifact %s deleted successfully.",
property, artifactId));
}
@DELETE
@Path("/namespaces/{namespace-id}/apps/{app-id}/{program-type}/{program-id}/metadata/properties")
public void removeProgramProperties(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("app-id") String appId,
@PathParam("program-type") String programType,
@PathParam("program-id") String programId) throws NotFoundException {
Id.Program program = Id.Program.from(Id.Application.from(namespaceId, appId),
ProgramType.valueOfCategoryName(programType), programId);
metadataAdmin.removeProperties(program);
responder.sendString(HttpResponseStatus.OK,
String.format("Metadata properties for program %s deleted successfully.", program));
}
@DELETE
@Path("/namespaces/{namespace-id}/apps/{app-id}/{program-type}/{program-id}/metadata/properties/{property}")
public void removeProgramProperty(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("app-id") String appId,
@PathParam("program-type") String programType,
@PathParam("program-id") String programId,
@PathParam("property") String property) throws NotFoundException {
Id.Program program = Id.Program.from(Id.Application.from(namespaceId, appId),
ProgramType.valueOfCategoryName(programType), programId);
metadataAdmin.removeProperties(program, property);
responder.sendString(HttpResponseStatus.OK,
String.format("Metadata property %s for program %s deleted successfully.", property, program));
}
@DELETE
@Path("/namespaces/{namespace-id}/datasets/{dataset-id}/metadata/properties")
public void removeDatasetProperties(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("dataset-id") String datasetId) throws NotFoundException {
Id.DatasetInstance dataset = Id.DatasetInstance.from(namespaceId, datasetId);
metadataAdmin.removeProperties(dataset);
responder.sendString(HttpResponseStatus.OK,
String.format("Metadata properties for dataset %s deleted successfully.", dataset));
}
@DELETE
@Path("/namespaces/{namespace-id}/datasets/{dataset-id}/metadata/properties/{property}")
public void removeDatasetProperty(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("dataset-id") String datasetId,
@PathParam("property") String property) throws NotFoundException {
Id.DatasetInstance dataset = Id.DatasetInstance.from(namespaceId, datasetId);
metadataAdmin.removeProperties(dataset, property);
responder.sendString(HttpResponseStatus.OK,
String.format("Metadata property %s for dataset %s deleted successfully.", property, dataset));
}
@DELETE
@Path("/namespaces/{namespace-id}/streams/{stream-id}/metadata/properties")
public void removeStreamProperties(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("stream-id") String streamId) throws NotFoundException {
Id.Stream stream = Id.Stream.from(namespaceId, streamId);
metadataAdmin.removeProperties(stream);
responder.sendString(HttpResponseStatus.OK,
String.format("Metadata properties for stream %s deleted successfully.", stream));
}
@DELETE
@Path("/namespaces/{namespace-id}/streams/{stream-id}/views/{view-id}/metadata/properties")
public void removeViewProperties(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("stream-id") String streamId,
@PathParam("view-id") String viewId) throws NotFoundException {
Id.Stream.View view = Id.Stream.View.from(namespaceId, streamId, viewId);
metadataAdmin.removeProperties(view);
responder.sendString(HttpResponseStatus.OK,
String.format("Metadata properties for view %s deleted successfully.", view));
}
@DELETE
@Path("/namespaces/{namespace-id}/streams/{stream-id}/metadata/properties/{property}")
public void removeStreamProperty(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("stream-id") String streamId,
@PathParam("property") String property) throws NotFoundException {
Id.Stream stream = Id.Stream.from(namespaceId, streamId);
metadataAdmin.removeProperties(stream, property);
responder.sendString(HttpResponseStatus.OK,
String.format("Metadata property %s for stream %s deleted successfully.", property, stream));
}
@DELETE
@Path("/namespaces/{namespace-id}/streams/{stream-id}/views/{view-id}/metadata/properties/{property}")
public void removeViewProperty(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("stream-id") String streamId,
@PathParam("view-id") String viewId,
@PathParam("property") String property) throws NotFoundException {
Id.Stream.View view = Id.Stream.View.from(namespaceId, streamId, viewId);
metadataAdmin.removeProperties(view, property);
responder.sendString(HttpResponseStatus.OK,
String.format("Metadata property %s for view %s deleted successfully.", property, view));
}
@POST
@Path("/namespaces/{namespace-id}/apps/{app-id}/metadata/tags")
public void addAppTags(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("app-id") String appId) throws BadRequestException, NotFoundException {
Id.Application app = Id.Application.from(namespaceId, appId);
metadataAdmin.addTags(app, readArray(request));
responder.sendString(HttpResponseStatus.OK,
String.format("Added tags to application %s successfully.", app));
}
@POST
@Path("/namespaces/{namespace-id}/artifacts/{artifact-name}/versions/{artifact-version}/metadata/tags")
public void addArtifactTags(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("artifact-name") String artifactName,
@PathParam("artifact-version") String artifactVersionStr)
throws BadRequestException, NotFoundException {
Id.Artifact artifactId = Id.Artifact.from(Id.Namespace.from(namespaceId), artifactName, artifactVersionStr);
metadataAdmin.addTags(artifactId, readArray(request));
responder.sendJson(HttpResponseStatus.OK,
String.format("Added tags to artifact %s successfully.", artifactId));
}
@POST
@Path("/namespaces/{namespace-id}/apps/{app-id}/{program-type}/{program-id}/metadata/tags")
public void addProgramTags(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("app-id") String appId,
@PathParam("program-type") String programType,
@PathParam("program-id") String programId) throws BadRequestException, NotFoundException {
Id.Program program = Id.Program.from(Id.Application.from(namespaceId, appId),
ProgramType.valueOfCategoryName(programType), programId);
metadataAdmin.addTags(program, readArray(request));
responder.sendString(HttpResponseStatus.OK,
String.format("Added tags to program %s successfully.", program));
}
@POST
@Path("/namespaces/{namespace-id}/datasets/{dataset-id}/metadata/tags")
public void addDatasetTags(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("dataset-id") String datasetId) throws BadRequestException, NotFoundException {
Id.DatasetInstance dataset = Id.DatasetInstance.from(namespaceId, datasetId);
metadataAdmin.addTags(dataset, readArray(request));
responder.sendString(HttpResponseStatus.OK,
String.format("Added tags to dataset %s successfully.", dataset));
}
@POST
@Path("/namespaces/{namespace-id}/streams/{stream-id}/metadata/tags")
public void addStreamTags(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("stream-id") String streamId) throws BadRequestException, NotFoundException {
Id.Stream stream = Id.Stream.from(namespaceId, streamId);
metadataAdmin.addTags(stream, readArray(request));
responder.sendString(HttpResponseStatus.OK,
String.format("Added tags to stream %s successfully.", stream));
}
@POST
@Path("/namespaces/{namespace-id}/streams/{stream-id}/views/{view-id}/metadata/tags")
public void addViewTags(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("stream-id") String streamId,
@PathParam("view-id") String viewId) throws NotFoundException, BadRequestException {
Id.Stream.View view = Id.Stream.View.from(namespaceId, streamId, viewId);
metadataAdmin.addTags(view, readArray(request));
responder.sendString(HttpResponseStatus.OK,
String.format("Added tags to view %s successfully", view));
}
@GET
@Path("/namespaces/{namespace-id}/apps/{app-id}/metadata/tags")
public void getAppTags(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("app-id") String appId,
@QueryParam("scope") String scope) throws NotFoundException, BadRequestException {
Id.Application app = Id.Application.from(namespaceId, appId);
responder.sendJson(HttpResponseStatus.OK, getTags(app, scope));
}
@GET
@Path("/namespaces/{namespace-id}/artifacts/{artifact-name}/versions/{artifact-version}/metadata/tags")
public void getArtifactTags(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("artifact-name") String artifactName,
@PathParam("artifact-version") String artifactVersionStr,
@QueryParam("scope") String scope)
throws BadRequestException, NotFoundException {
Id.Artifact artifactId = Id.Artifact.from(Id.Namespace.from(namespaceId), artifactName, artifactVersionStr);
responder.sendJson(HttpResponseStatus.OK, getTags(artifactId, scope));
}
@GET
@Path("/namespaces/{namespace-id}/apps/{app-id}/{program-type}/{program-id}/metadata/tags")
public void getProgramTags(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("app-id") String appId,
@PathParam("program-type") String programType,
@PathParam("program-id") String programId,
@QueryParam("scope") String scope) throws NotFoundException, BadRequestException {
Id.Program program = Id.Program.from(Id.Application.from(namespaceId, appId),
ProgramType.valueOfCategoryName(programType), programId);
responder.sendJson(HttpResponseStatus.OK, getTags(program, scope));
}
@GET
@Path("/namespaces/{namespace-id}/datasets/{dataset-id}/metadata/tags")
public void getDatasetTags(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("dataset-id") String datasetId,
@QueryParam("scope") String scope) throws NotFoundException, BadRequestException {
Id.DatasetInstance dataset = Id.DatasetInstance.from(namespaceId, datasetId);
responder.sendJson(HttpResponseStatus.OK, getTags(dataset, scope));
}
@GET
@Path("/namespaces/{namespace-id}/streams/{stream-id}/metadata/tags")
public void getStreamTags(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("stream-id") String streamId,
@QueryParam("scope") String scope) throws NotFoundException, BadRequestException {
Id.Stream stream = Id.Stream.from(namespaceId, streamId);
responder.sendJson(HttpResponseStatus.OK, getTags(stream, scope));
}
@GET
@Path("/namespaces/{namespace-id}/streams/{stream-id}/views/{view-id}/metadata/tags")
public void getViewTags(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("stream-id") String streamId,
@PathParam("view-id") String viewId,
@QueryParam("scope") String scope) throws NotFoundException, BadRequestException {
Id.Stream.View view = Id.Stream.View.from(namespaceId, streamId, viewId);
responder.sendJson(HttpResponseStatus.OK, getTags(view, scope));
}
@DELETE
@Path("/namespaces/{namespace-id}/apps/{app-id}/metadata/tags")
public void removeAppTags(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("app-id") String appId) throws NotFoundException {
Id.Application app = Id.Application.from(namespaceId, appId);
metadataAdmin.removeTags(app);
responder.sendString(HttpResponseStatus.OK,
String.format("Tags for app %s deleted successfully.", app));
}
@DELETE
@Path("/namespaces/{namespace-id}/apps/{app-id}/metadata/tags/{tag}")
public void removeAppTag(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("app-id") String appId,
@PathParam("tag") String tag) throws NotFoundException {
Id.Application app = Id.Application.from(namespaceId, appId);
metadataAdmin.removeTags(app, tag);
responder.sendString(HttpResponseStatus.OK,
String.format("Tag %s for app %s deleted successfully.", tag, app));
}
@DELETE
@Path("/namespaces/{namespace-id}/artifacts/{artifact-name}/versions/{artifact-version}/metadata/tags")
public void removeArtifactTags(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("artifact-name") String artifactName,
@PathParam("artifact-version") String artifactVersionStr) throws NotFoundException {
Id.Artifact artifactId = Id.Artifact.from(Id.Namespace.from(namespaceId), artifactName, artifactVersionStr);
metadataAdmin.removeTags(artifactId);
responder.sendString(HttpResponseStatus.OK,
String.format("Tags for artifact %s deleted successfully.", artifactId));
}
@DELETE
@Path("/namespaces/{namespace-id}/artifacts/{artifact-name}/versions/{artifact-version}/metadata/tags/{tag}")
public void removeArtifactTag(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("artifact-name") String artifactName,
@PathParam("artifact-version") String artifactVersionStr,
@PathParam("tag") String tag) throws NotFoundException {
Id.Artifact artifactId = Id.Artifact.from(Id.Namespace.from(namespaceId), artifactName, artifactVersionStr);
metadataAdmin.removeTags(artifactId, tag);
responder.sendString(HttpResponseStatus.OK,
String.format("Tags %s for artifact %s deleted successfully.", tag, artifactId));
}
@DELETE
@Path("/namespaces/{namespace-id}/apps/{app-id}/{program-type}/{program-id}/metadata/tags")
public void removeProgramTags(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("app-id") String appId,
@PathParam("program-type") String programType,
@PathParam("program-id") String programId) throws NotFoundException {
Id.Program program = Id.Program.from(Id.Application.from(namespaceId, appId),
ProgramType.valueOfCategoryName(programType), programId);
metadataAdmin.removeTags(program);
responder.sendString(HttpResponseStatus.OK,
String.format("Tags for program %s deleted successfully.", program));
}
@DELETE
@Path("/namespaces/{namespace-id}/apps/{app-id}/{program-type}/{program-id}/metadata/tags/{tag}")
public void removeProgramTag(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("app-id") String appId,
@PathParam("program-type") String programType,
@PathParam("program-id") String programId,
@PathParam("tag") String tag) throws NotFoundException {
Id.Program program = Id.Program.from(Id.Application.from(namespaceId, appId),
ProgramType.valueOfCategoryName(programType), programId);
metadataAdmin.removeTags(program, tag);
responder.sendString(HttpResponseStatus.OK,
String.format("Tag %s for program %s deleted successfully.", tag, program));
}
@DELETE
@Path("/namespaces/{namespace-id}/datasets/{dataset-id}/metadata/tags")
public void removeDatasetTags(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("dataset-id") String datasetId) throws NotFoundException {
Id.DatasetInstance dataset = Id.DatasetInstance.from(namespaceId, datasetId);
metadataAdmin.removeTags(dataset);
responder.sendString(HttpResponseStatus.OK,
String.format("Tags for dataset %s deleted successfully.", dataset));
}
@DELETE
@Path("/namespaces/{namespace-id}/datasets/{dataset-id}/metadata/tags/{tag}")
public void removeDatasetTag(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("dataset-id") String datasetId,
@PathParam("tag") String tag) throws NotFoundException {
Id.DatasetInstance dataset = Id.DatasetInstance.from(namespaceId, datasetId);
metadataAdmin.removeTags(dataset, tag);
responder.sendString(HttpResponseStatus.OK,
String.format("Tag %s for dataset %s deleted successfully.", tag, dataset));
}
@DELETE
@Path("/namespaces/{namespace-id}/streams/{stream-id}/metadata/tags")
public void removeStreamTags(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("stream-id") String streamId) throws NotFoundException {
Id.Stream stream = Id.Stream.from(namespaceId, streamId);
metadataAdmin.removeTags(stream);
responder.sendString(HttpResponseStatus.OK,
String.format("Tags for stream %s deleted successfully.", stream));
}
@DELETE
@Path("/namespaces/{namespace-id}/streams/{stream-id}/views/{view-id}/metadata/tags")
public void removeViewTags(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("stream-id") String streamId,
@PathParam("view-id") String viewId) throws NotFoundException {
Id.Stream.View view = Id.Stream.View.from(namespaceId, streamId, viewId);
metadataAdmin.removeTags(view);
responder.sendString(HttpResponseStatus.OK,
String.format("Tags for view %s deleted successfully.", view));
}
@DELETE
@Path("/namespaces/{namespace-id}/streams/{stream-id}/metadata/tags/{tag}")
public void removeStreamTag(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("stream-id") String streamId,
@PathParam("tag") String tag) throws NotFoundException {
Id.Stream stream = Id.Stream.from(namespaceId, streamId);
metadataAdmin.removeTags(stream, tag);
responder.sendString(HttpResponseStatus.OK,
String.format("Tag %s for stream %s deleted successfully.", tag, stream));
}
@DELETE
@Path("/namespaces/{namespace-id}/streams/{stream-id}/views/{view-id}/metadata/tags/{tag}")
public void removeViewTag(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@PathParam("stream-id") String streamId,
@PathParam("view-id") String viewId,
@PathParam("tag") String tag) throws NotFoundException {
Id.Stream.View view = Id.Stream.View.from(namespaceId, streamId, viewId);
metadataAdmin.removeTags(view, tag);
responder.sendString(HttpResponseStatus.OK,
String.format("Tag %s for view %s deleted successfully.", tag, view));
}
private Map<String, String> readMetadata(HttpRequest request) throws BadRequestException {
ChannelBuffer content = request.getContent();
if (!content.readable()) {
throw new BadRequestException("Unable to read metadata properties from the request.");
}
Map<String, String> metadata;
try (Reader reader = new InputStreamReader(new ChannelBufferInputStream(content), Charsets.UTF_8)) {
metadata = GSON.fromJson(reader, MAP_STRING_STRING_TYPE);
} catch (IOException e) {
throw new BadRequestException("Unable to read metadata properties from the request.", e);
}
if (metadata == null) {
throw new BadRequestException("Null metadata was read from the request");
}
return metadata;
}
private String[] readArray(HttpRequest request) throws BadRequestException {
ChannelBuffer content = request.getContent();
if (!content.readable()) {
throw new BadRequestException("Unable to read a list of tags from the request.");
}
List<String> toReturn;
try (Reader reader = new InputStreamReader(new ChannelBufferInputStream(content), Charsets.UTF_8)) {
toReturn = GSON.fromJson(reader, LIST_STRING_TYPE);
} catch (IOException e) {
throw new BadRequestException("Unable to read a list of tags from the request.", e);
}
if (toReturn == null) {
throw new BadRequestException("Null tags were read from the request.");
}
return toReturn.toArray(new String[toReturn.size()]);
}
// *** Search endpoints ***
@GET
@Path("/namespaces/{namespace-id}/metadata/search")
public void searchMetadata(HttpRequest request, HttpResponder responder,
@PathParam("namespace-id") String namespaceId,
@QueryParam("query") String searchQuery,
@QueryParam("target") List<String> targets) throws Exception {
Set<MetadataSearchTargetType> types = ImmutableSet.of();
if (targets != null) {
types = ImmutableSet.copyOf(Iterables.transform(targets, STRING_TO_TARGET_TYPE));
}
Set<MetadataSearchResultRecord> results = metadataAdmin.searchMetadata(namespaceId,
URLDecoder.decode(searchQuery, "UTF-8"),
types);
responder.sendJson(HttpResponseStatus.OK, results, SET_METADATA_SEARCH_RESULT_TYPE, GSON);
}
private Set<MetadataRecord> getMetadata(Id.NamespacedId entityId,
@Nullable String scope) throws NotFoundException, BadRequestException {
return (scope == null) ? metadataAdmin.getMetadata(entityId) :
metadataAdmin.getMetadata(validateScope(scope), entityId);
}
private Map<String, String> getProperties(Id.NamespacedId entityId,
@Nullable String scope) throws NotFoundException, BadRequestException {
return (scope == null) ? metadataAdmin.getProperties(entityId) :
metadataAdmin.getProperties(validateScope(scope), entityId);
}
private Set<String> getTags(Id.NamespacedId entityId,
@Nullable String scope) throws NotFoundException, BadRequestException {
return (scope == null) ? metadataAdmin.getTags(entityId) : metadataAdmin.getTags(validateScope(scope), entityId);
}
private MetadataScope validateScope(String scope) throws BadRequestException {
try {
return MetadataScope.valueOf(scope.toUpperCase());
} catch (IllegalArgumentException e) {
throw new BadRequestException(String.format("Invalid metadata scope '%s'. Expected '%s' or '%s'",
scope, MetadataScope.USER, MetadataScope.SYSTEM));
}
}
}