View Javadoc

1   /*
2    * Copyright 2010 Ning, Inc.
3    *
4    * Ning licenses this file to you under the Apache License, version 2.0
5    * (the "License"); you may not use this file except in compliance with the
6    * License.  You may obtain a copy of the License at:
7    *
8    *    http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  
17  package com.ning.metrics.goodwill.endpoint;
18  
19  import com.google.inject.Inject;
20  import com.ning.metrics.goodwill.access.GoodwillSchema;
21  import com.ning.metrics.goodwill.binder.config.GoodwillConfig;
22  import com.ning.metrics.goodwill.modules.ThriftRegistrar;
23  import com.ning.metrics.goodwill.sink.GoodwillSink;
24  import com.ning.metrics.goodwill.store.GoodwillStore;
25  import com.sun.jersey.api.view.Viewable;
26  import org.apache.log4j.Logger;
27  
28  import javax.annotation.Nullable;
29  import javax.ws.rs.Consumes;
30  import javax.ws.rs.DELETE;
31  import javax.ws.rs.GET;
32  import javax.ws.rs.POST;
33  import javax.ws.rs.PUT;
34  import javax.ws.rs.Path;
35  import javax.ws.rs.PathParam;
36  import javax.ws.rs.Produces;
37  import javax.ws.rs.core.MediaType;
38  import javax.ws.rs.core.Response;
39  import java.io.IOException;
40  
41  @Path("registrar")
42  public class Registrar
43  {
44      private Logger log = Logger.getLogger(Registrar.class);
45  
46      private GoodwillStore store;
47      private final GoodwillSink sink;
48      private final GoodwillConfig config;
49  
50      @Inject
51      public Registrar(
52          GoodwillConfig config,
53          GoodwillStore store,
54          @Nullable GoodwillSink sink
55      )
56      {
57          this.config = config;
58          this.store = store;
59          this.sink = sink;
60  
61          if (sink != null) {
62              this.store.setSink(sink);
63          }
64      }
65  
66      /*
67       * UI
68       */
69  
70      @GET
71      @Produces(MediaType.TEXT_HTML)
72      public Viewable getAll() throws IOException
73      {
74          ThriftRegistrar registrar = new ThriftRegistrar(store.toJSON());
75          registrar.setActionCoreURL(config.getActionCoreURL());
76  
77          return new Viewable("/registrar/type.jsp", registrar);
78      }
79  
80      /*
81       * REST API
82       */
83  
84      @GET
85      @Produces("application/json")
86      public Response getAllJson() throws IOException
87      {
88          return Response.ok(store.toJSON().toString()).type(MediaType.APPLICATION_JSON_TYPE).build();
89      }
90  
91      @GET
92      @Produces("application/json")
93      @Path("/{type}/")
94      public Response getTypeJson(@PathParam("type") String typeName) throws IOException
95      {
96          if (typeName == null) {
97              return Response.ok(store.toJSON().toString()).type(MediaType.APPLICATION_JSON_TYPE).build();
98          }
99          else {
100             GoodwillSchema typeFound = store.findByName(typeName);
101             if (typeFound != null) {
102                 return Response.ok(typeFound.toJSON().toString()).type(MediaType.APPLICATION_JSON_TYPE).build();
103             }
104         }
105 
106         return Response.status(Response.Status.NOT_FOUND).build();
107     }
108 
109     @DELETE
110     @Path("/{type}/")
111     public Response deleteType(@PathParam("type") String typeName) throws IOException
112     {
113         if (!config.allowDeleteEvent()) {
114             return Response.status(Response.Status.FORBIDDEN).build();
115         }
116 
117         if (typeName == null) {
118             return Response.status(Response.Status.BAD_REQUEST).build();
119         }
120         else {
121             GoodwillSchema typeFound = store.findByName(typeName);
122             if (typeFound != null) {
123                 if (store.deleteType(typeFound)) {
124                     return Response.noContent().build();
125                 }
126                 else {
127                     return Response.status(Response.Status.SERVICE_UNAVAILABLE).build();
128                 }
129             }
130             else {
131                 // Don't! The condition is not necessarily permanent!
132                 //return Response.status(Response.Status.GONE)
133                 return Response.status(Response.Status.NOT_FOUND).build();
134             }
135         }
136     }
137 
138     @POST
139     @Consumes("application/json")
140     public Response post(
141         String jsonThriftTypeString
142     )
143     {
144         try {
145             GoodwillSchema schema = GoodwillSchema.decode(jsonThriftTypeString);
146             store.addType(schema);
147             log.info(String.format("Created new ThriftType <%s> from JSON <%s>", schema.toString(), jsonThriftTypeString));
148         }
149         catch (IOException e) {
150             log.warn(String.format("Malformatted JSON: %s (%s)", jsonThriftTypeString, e));
151             return Response.status(Response.Status.BAD_REQUEST).build();
152         }
153 
154         return Response.status(Response.Status.CREATED).build();
155     }
156 
157     @PUT
158     @Consumes("application/json")
159     public Response put(
160         String jsonThriftTypeString
161     )
162     {
163         try {
164             GoodwillSchema thriftType = GoodwillSchema.decode(jsonThriftTypeString);
165             store.updateType(thriftType);
166             log.info(String.format("Updated ThriftType <%s> from JSON <%s>", thriftType.toString(), jsonThriftTypeString));
167         }
168         catch (IOException e) {
169             log.warn(String.format("Malformatted JSON: %s", jsonThriftTypeString));
170             return Response.status(Response.Status.BAD_REQUEST).build();
171         }
172 
173         return Response.status(Response.Status.ACCEPTED).build();
174     }
175 }