View Javadoc

1   /**
2    * Copyright (c) 2002-2011 "Neo Technology,"
3    * Network Engine for Objects in Lund AB [http://neotechnology.com]
4    *
5    * This file is part of Neo4j.
6    *
7    * Neo4j is free software: you can redistribute it and/or modify
8    * it under the terms of the GNU General Public License as published by
9    * the Free Software Foundation, either version 3 of the License, or
10   * (at your option) any later version.
11   *
12   * This program is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Public License for more details.
16   *
17   * You should have received a copy of the GNU General Public License
18   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19   */
20  package org.neo4j.server.webadmin.rest;
21  
22  import java.io.UnsupportedEncodingException;
23  import java.lang.management.ManagementFactory;
24  import java.net.URLDecoder;
25  import java.util.ArrayList;
26  import java.util.Collection;
27  
28  import javax.management.MBeanServer;
29  import javax.management.MalformedObjectNameException;
30  import javax.management.ObjectName;
31  import javax.ws.rs.Consumes;
32  import javax.ws.rs.FormParam;
33  import javax.ws.rs.GET;
34  import javax.ws.rs.POST;
35  import javax.ws.rs.Path;
36  import javax.ws.rs.PathParam;
37  import javax.ws.rs.Produces;
38  import javax.ws.rs.WebApplicationException;
39  import javax.ws.rs.core.Context;
40  import javax.ws.rs.core.MediaType;
41  import javax.ws.rs.core.Response;
42  
43  import org.neo4j.jmx.Kernel;
44  import org.neo4j.server.database.Database;
45  import org.neo4j.server.database.DatabaseBlockedException;
46  import org.neo4j.server.rest.domain.JsonHelper;
47  import org.neo4j.server.rest.repr.BadInputException;
48  import org.neo4j.server.rest.repr.InputFormat;
49  import org.neo4j.server.rest.repr.ListRepresentation;
50  import org.neo4j.server.rest.repr.OutputFormat;
51  import org.neo4j.server.webadmin.rest.representations.JmxDomainRepresentation;
52  import org.neo4j.server.webadmin.rest.representations.JmxMBeanRepresentation;
53  import org.neo4j.server.webadmin.rest.representations.ServiceDefinitionRepresentation;
54  
55  @Path( JmxService.ROOT_PATH )
56  public class JmxService implements AdvertisableService
57  {
58      public static final String ROOT_PATH = "server/jmx";
59  
60      public static final String DOMAINS_PATH = "/domain";
61      public static final String DOMAIN_TEMPLATE = DOMAINS_PATH + "/{domain}";
62      public static final String BEAN_TEMPLATE = DOMAIN_TEMPLATE + "/{objectName}";
63      public static final String QUERY_PATH = "/query";
64      public static final String KERNEL_NAME_PATH = "/kernelquery";
65      private final OutputFormat output;
66  
67      public JmxService( @Context OutputFormat output, @Context InputFormat input )
68      {
69          this.output = output;
70      }
71  
72      @GET
73      public Response getServiceDefinition()
74      {
75          ServiceDefinitionRepresentation serviceDef = new ServiceDefinitionRepresentation( ROOT_PATH );
76          serviceDef.resourceUri( "domains", JmxService.DOMAINS_PATH );
77          serviceDef.resourceTemplate( "domain", JmxService.DOMAIN_TEMPLATE );
78          serviceDef.resourceTemplate( "bean", JmxService.BEAN_TEMPLATE );
79          serviceDef.resourceUri( "query", JmxService.QUERY_PATH );
80          serviceDef.resourceUri( "kernelquery", JmxService.KERNEL_NAME_PATH );
81  
82          return output.ok( serviceDef );
83      }
84  
85      @GET
86      @Path( DOMAINS_PATH )
87      public Response listDomains() throws NullPointerException
88      {
89          MBeanServer server = ManagementFactory.getPlatformMBeanServer();
90          ListRepresentation domains = ListRepresentation.strings( server.getDomains() );
91          return output.ok( domains );
92      }
93  
94      @GET
95      @Path( DOMAIN_TEMPLATE )
96      public Response getDomain( @PathParam( "domain" ) String domainName )
97      {
98          MBeanServer server = ManagementFactory.getPlatformMBeanServer();
99  
100         JmxDomainRepresentation domain = new JmxDomainRepresentation( domainName );
101 
102         for ( Object objName : server.queryNames( null, null ) )
103         {
104             if ( objName.toString().startsWith( domainName ) )
105             {
106                 domain.addBean( (ObjectName)objName );
107             }
108         }
109 
110         return output.ok( domain );
111     }
112 
113     @GET
114     @Path( BEAN_TEMPLATE )
115     public Response getBean( @PathParam( "domain" ) String domainName, @PathParam( "objectName" ) String objectName )
116     {
117         MBeanServer server = ManagementFactory.getPlatformMBeanServer();
118 
119         ArrayList<JmxMBeanRepresentation> beans = new ArrayList<JmxMBeanRepresentation>();
120         for ( Object objName : server.queryNames( createObjectName( domainName, objectName ), null ) )
121         {
122             beans.add( new JmxMBeanRepresentation( (ObjectName)objName ) );
123         }
124 
125         return output.ok( new ListRepresentation( "bean", beans ) );
126     }
127 
128     private ObjectName createObjectName( final String domainName, final String objectName )
129     {
130         try
131         {
132             return new ObjectName( domainName + ":" + URLDecoder.decode( objectName, "UTF-8" ) );
133         } catch ( MalformedObjectNameException e )
134         {
135             throw new WebApplicationException( e, 400 );
136         } catch ( UnsupportedEncodingException e )
137         {
138             throw new WebApplicationException( e, 400 );
139         }
140     }
141 
142 
143     @POST
144     @Consumes( MediaType.APPLICATION_JSON )
145     @Path( QUERY_PATH )
146     @SuppressWarnings( "unchecked" )
147     public Response queryBeans( String query )
148     {
149         try
150         {
151             MBeanServer server = ManagementFactory.getPlatformMBeanServer();
152 
153 
154             String json = dodgeStartingUnicodeMarker( query );
155             Collection<Object> queries = (Collection<Object>)JsonHelper.jsonToSingleValue( json );
156 
157             ArrayList<JmxMBeanRepresentation> beans = new ArrayList<JmxMBeanRepresentation>();
158             for ( Object queryObj : queries )
159             {
160                 assert queryObj instanceof String;
161                 for ( Object objName : server.queryNames( new ObjectName( (String)queryObj ), null ) )
162                 {
163                     beans.add( new JmxMBeanRepresentation( (ObjectName)objName ) );
164                 }
165             }
166 
167             return output.ok( new ListRepresentation( "jmxBean", beans ) );
168         } catch ( MalformedObjectNameException e )
169         {
170             return output.badRequest( e );
171         } catch ( BadInputException e )
172         {
173             return output.badRequest( e );
174         }
175 
176     }
177 
178     @POST
179     @Produces( MediaType.APPLICATION_JSON )
180     @Consumes( MediaType.APPLICATION_FORM_URLENCODED )
181     @Path( QUERY_PATH )
182     public Response formQueryBeans( @FormParam( "value" ) String data )
183     {
184         return queryBeans( data );
185     }
186 
187     @GET
188     @Produces( MediaType.APPLICATION_JSON )
189     @Path( KERNEL_NAME_PATH )
190     public Response currentKernelInstance( @Context Database database ) throws DatabaseBlockedException
191     {
192         Kernel kernelBean = database.graph.getManagementBean( Kernel.class );
193         return Response.ok( "\"" + kernelBean.getMBeanQuery().toString() + "\"" ).type( MediaType.APPLICATION_JSON ).build();
194     }
195 
196     public String getName()
197     {
198         return "jmx";
199     }
200 
201     public String getServerPath()
202     {
203         return ROOT_PATH;
204     }
205 
206     private static String dodgeStartingUnicodeMarker( String string )
207     {
208         if ( string != null && string.length() > 0 )
209         {
210             if ( string.charAt( 0 ) == 0xfeff )
211             {
212                 return string.substring( 1 );
213             }
214         }
215         return string;
216     }
217 }