View Javadoc

1   /*
2    ~ Copyright 2006-2007 Nicolas De Loof.
3    ~
4    ~ Licensed under the Apache License, Version 2.0 (the "License");
5    ~ you may not use this file except in compliance with the License.
6    ~ 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,
12   ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   ~ See the License for the specific language governing permissions and
14   ~ limitations under the License.
15   */
16  package org.jmonit.web;
17  
18  import java.io.IOException;
19  import java.util.ArrayList;
20  import java.util.Collection;
21  import java.util.HashMap;
22  import java.util.List;
23  import java.util.Map;
24  import java.util.StringTokenizer;
25  
26  import javax.servlet.ServletException;
27  import javax.servlet.http.HttpServlet;
28  import javax.servlet.http.HttpServletRequest;
29  import javax.servlet.http.HttpServletResponse;
30  
31  import org.jmonit.Monitor;
32  import org.jmonit.Monitoring;
33  import org.jmonit.Repository;
34  import org.jmonit.log.Log;
35  import org.jmonit.reporting.JSonRenderer;
36  import org.jmonit.reporting.Renderer;
37  import org.jmonit.spi.PluginManager;
38  
39  /**
40   * @author <a href="mailto:nicolas.deloof@gmail.com">Nicolas De Loof</a>
41   */
42  public class RestServlet
43      extends HttpServlet
44  {
45      /** logger */
46      private static Log log = Log.getLog( RestServlet.class );
47  
48      /**
49       *
50       */
51      private static final long serialVersionUID = 1L;
52  
53      /**
54       *
55       */
56      private static final String TAG = "/tag/";
57  
58      /**
59       *
60       */
61      private static final String MONITORS = "/monitors";
62  
63      private static final String MONITOR = "/monitor/";
64  
65      private Map<String, Renderer> renderers = new HashMap<String, Renderer>();
66  
67      private Repository repository = Monitoring.getRepository();
68      {
69          renderers.put( "application/json", new JSonRenderer( null ) );
70          renderers.put( "text/javascript", new JSonRenderer( null ) );
71      }
72  
73      /**
74       * {@inheritDoc}
75       * 
76       * @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest,
77       * javax.servlet.http.HttpServletResponse)
78       */
79      protected void service( HttpServletRequest request, HttpServletResponse response )
80          throws ServletException, IOException
81      {
82          List<String> mimeTypes = MimeUtils.getMimeTypes( request );
83          restService( request.getPathInfo(), mimeTypes, response );
84      }
85  
86      protected void restService( String path, List<String> mimeTypes, HttpServletResponse response )
87          throws IOException
88      {
89          Renderer renderer = getRenderer( mimeTypes, response );
90          if ( renderer == null )
91          {
92              response.sendError( HttpServletResponse.SC_NOT_IMPLEMENTED );
93              return;
94          }
95          StringBuffer location = new StringBuffer( path );
96          Object resource = getRestResource( location );
97          if ( resource == null )
98          {
99              // TODO check if this is the REST-way to handle unsupported path
100             response.sendError( HttpServletResponse.SC_BAD_REQUEST );
101             return;
102         }
103 
104         if ( location.length() > 0 && location.charAt( 0 ) == '/' )
105         {
106             location.delete( 0, 1 );
107         }
108         if ( log.isDebugEnabled() )
109         {
110             log.debug( "request for " + path );
111             log.debug( "resource is " + path.substring( 0, path.length() - location.length() ) );
112             log.debug( "features are " + location.toString() );
113         }
114         Collection<Class> features = getFeatures( location.toString() );
115 
116         response.addHeader( "Cache-Control", "no-cache" );
117         if ( resource instanceof Collection )
118         {
119             Collection<Monitor> collection = (Collection<Monitor>) resource;
120             renderer.render( new MonitorsIterator( collection.iterator(), features ) );
121         }
122         if ( resource instanceof Monitor )
123         {
124             Collection<Monitor> collection = new ArrayList<Monitor>();
125             collection.add( (Monitor) resource );
126             renderer.render( new MonitorsIterator( collection.iterator(), features ) );
127         }
128     }
129 
130     /**
131      * Find the jmonit resource pointed by the request path.
132      * 
133      * @param request HTTP request
134      * @return a resource objet
135      */
136     protected Object getRestResource( StringBuffer path )
137     {
138         if ( path.toString().startsWith( MONITOR ) )
139         {
140             path.delete( 0, MONITOR.length() - 1 );
141             String name;
142             int i = path.indexOf( "/" );
143             if ( i > 0 )
144             {
145                 name = path.substring( 0, i );
146                 path.delete( 0, i + 1 );
147             }
148             else
149             {
150                 name = path.toString();
151                 path.setLength( 0 );
152             }
153             Monitor monitor = repository.getMonitor( name );
154             return monitor;
155         }
156 
157         if ( path.toString().startsWith( MONITORS ) )
158         {
159             Collection<Monitor> monitors = null;
160             path.delete( 0, MONITORS.length() );
161 
162             if ( path.toString().startsWith( TAG ) )
163             {
164                 path.delete( 0, TAG.length() );
165                 String tag;
166                 int i = path.indexOf( "/" );
167                 if ( i > 0 )
168                 {
169                     tag = path.substring( 0, i );
170                     path.delete( 0, i + 1 );
171                 }
172                 else
173                 {
174                     tag = path.toString();
175                     path.setLength( 0 );
176                 }
177                 monitors = repository.getMonitorsWithTag( tag );
178             }
179             else
180             {
181                 monitors = repository.getMonitors();
182             }
183             return monitors;
184         }
185         else
186         {
187             // Unsupported
188             return null;
189         }
190     }
191 
192     private Collection<Class> getFeatures( String path )
193     {
194         if ( path.charAt( 0 ) == '/' )
195         {
196             path = path.substring( 1 );
197         }
198 
199         PluginManager manager = Monitoring.getRepository().getFeatureManager();
200         Collection<Class> features = new ArrayList<Class>();
201         StringTokenizer tokenizer = new StringTokenizer( path, "+" );
202         while ( tokenizer.hasMoreTokens() )
203         {
204             Class feature = manager.getFeature( tokenizer.nextToken() );
205             if ( feature != null )
206             {
207                 features.add( feature );
208             }
209         }
210         return features;
211     }
212 
213     /**
214      * Find the best renderer according to the accept header (mime-type)
215      * 
216      * @param request HTTP request
217      * @param response HTTP response
218      * @return a renderer
219      * @throws IOException some error occured
220      */
221     protected Renderer getRenderer( List<String> mimeTypes, HttpServletResponse response )
222         throws IOException
223     {
224         for ( String mimeType : mimeTypes )
225         {
226             Renderer clonable = renderers.get( mimeType );
227             if ( clonable == null )
228             {
229                 continue;
230             }
231             Renderer renderer = clonable.createNew( response.getWriter() );
232             response.setContentType( mimeType );
233             if ( log.isDebugEnabled() )
234             {
235                 log.debug( "rendering resource with " + renderer.getClass().getName() );
236             }
237             return renderer;
238         }
239         return null;
240     }
241 }