/* * Copyright © 2014-2015 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.gateway.handlers; import co.cask.cdap.common.conf.Constants; import co.cask.cdap.notifications.feeds.NotificationFeedException; import co.cask.cdap.notifications.feeds.NotificationFeedManager; import co.cask.cdap.notifications.feeds.NotificationFeedNotFoundException; import co.cask.cdap.proto.Id; import co.cask.http.AbstractHttpHandler; import co.cask.http.HttpResponder; import com.google.common.base.Charsets; import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; 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 org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.util.List; import javax.annotation.Nullable; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; /** * HTTP handler to access the service managing {@link Id.NotificationFeed} objects. * These endpoints are only reachable internally. */ @Path(Constants.Gateway.API_VERSION_3 + "/namespaces/{namespace-id}") public class NotificationFeedHttpHandler extends AbstractHttpHandler { private static final Logger LOG = LoggerFactory.getLogger(NotificationFeedHttpHandler.class); private static final Gson GSON = new Gson(); private final NotificationFeedManager feedManager; @Inject public NotificationFeedHttpHandler(NotificationFeedManager feedManager) { this.feedManager = feedManager; } @PUT @Path("/feeds/categories/{feed-category}/names/{feed-name}") public void createFeed(HttpRequest request, HttpResponder responder, @PathParam("namespace-id") String namespaceId, @PathParam("feed-category") String category, @PathParam("feed-name") String name) { try { Id.NotificationFeed combinedFeed; try { Id.NotificationFeed feed = parseBody(request, Id.NotificationFeed.class); combinedFeed = new Id.NotificationFeed.Builder() .setNamespaceId(namespaceId) .setCategory(category) .setName(name) .setDescription(feed == null ? null : feed.getDescription()) .build(); } catch (IllegalArgumentException e) { responder.sendString(HttpResponseStatus.BAD_REQUEST, String.format("Could not create Notification Feed. %s", e.getMessage())); return; } if (feedManager.createFeed(combinedFeed)) { responder.sendString(HttpResponseStatus.OK, "Notification Feed created successfully"); } else { LOG.trace("Notification Feed already exists."); responder.sendString(HttpResponseStatus.OK, "Notification Feed already exists."); } } catch (NotificationFeedException e) { LOG.error("Could not create notification feed.", e); responder.sendString(HttpResponseStatus.INTERNAL_SERVER_ERROR, e.getMessage()); } catch (JsonSyntaxException e) { responder.sendString(HttpResponseStatus.BAD_REQUEST, "Invalid json object provided in request body."); } catch (IOException e) { LOG.error("Failed to read Notification feed request body.", e); responder.sendString(HttpResponseStatus.INTERNAL_SERVER_ERROR, e.getMessage()); } catch (Throwable t) { LOG.debug("Error in creating notification feed.", t); responder.sendString(HttpResponseStatus.INTERNAL_SERVER_ERROR, t.getMessage()); } } @DELETE @Path("/feeds/categories/{feed-category}/names/{feed-name}") public void deleteFeed(HttpRequest request, HttpResponder responder, @PathParam("namespace-id") String namespaceId, @PathParam("feed-category") String category, @PathParam("feed-name") String name) { try { Id.NotificationFeed feed; try { feed = new Id.NotificationFeed.Builder() .setNamespaceId(namespaceId) .setCategory(category) .setName(name) .build(); } catch (IllegalArgumentException e) { responder.sendString(HttpResponseStatus.BAD_REQUEST, e.getMessage()); return; } feedManager.deleteFeed(feed); responder.sendStatus(HttpResponseStatus.OK); } catch (NotificationFeedNotFoundException e) { responder.sendStatus(HttpResponseStatus.NOT_FOUND); } catch (NotificationFeedException e) { responder.sendString(HttpResponseStatus.INTERNAL_SERVER_ERROR, String.format("Could not delete Notification Feed. %s", e.getMessage())); } catch (Throwable t) { LOG.debug("Error in deleting notification feed.", t); responder.sendString(HttpResponseStatus.INTERNAL_SERVER_ERROR, t.getMessage()); } } @GET @Path("/feeds/categories/{feed-category}/names/{feed-name}") public void getFeed(HttpRequest request, HttpResponder responder, @PathParam("namespace-id") String namespaceId, @PathParam("feed-category") String category, @PathParam("feed-name") String name) { try { Id.NotificationFeed feed; try { feed = new Id.NotificationFeed.Builder() .setNamespaceId(namespaceId) .setCategory(category) .setName(name) .build(); } catch (IllegalArgumentException e) { responder.sendString(HttpResponseStatus.BAD_REQUEST, e.getMessage()); return; } responder.sendJson(HttpResponseStatus.OK, feedManager.getFeed(feed)); } catch (NotificationFeedNotFoundException e) { responder.sendStatus(HttpResponseStatus.NOT_FOUND); } catch (NotificationFeedException e) { responder.sendString(HttpResponseStatus.INTERNAL_SERVER_ERROR, String.format("Could not check subscribe permission for Notification Feed. %s", e.getMessage())); } catch (Throwable t) { LOG.debug("Error in getting notification feed.", t); responder.sendString(HttpResponseStatus.INTERNAL_SERVER_ERROR, t.getMessage()); } } @GET @Path("/feeds") public void listFeeds(HttpRequest request, HttpResponder responder, @PathParam("namespace-id") String namespaceId) { try { List<Id.NotificationFeed> feeds = feedManager.listFeeds(Id.Namespace.from(namespaceId)); responder.sendJson(HttpResponseStatus.OK, feeds); } catch (NotificationFeedException e) { responder.sendString(HttpResponseStatus.INTERNAL_SERVER_ERROR, String.format("Could not check subscribe permission for Notification Feed. %s", e.getMessage())); } catch (Throwable t) { LOG.debug("Error in listing notification feeds.", t); responder.sendString(HttpResponseStatus.INTERNAL_SERVER_ERROR, t.getMessage()); } } @Nullable private <T> T parseBody(HttpRequest request, Class<T> type) throws IOException { ChannelBuffer content = request.getContent(); if (!content.readable()) { return null; } try (Reader reader = new InputStreamReader(new ChannelBufferInputStream(content), Charsets.UTF_8)) { return GSON.fromJson(reader, type); } catch (JsonSyntaxException e) { LOG.debug("Failed to parse body on {} as {}", request.getUri(), type, e); throw e; } } }