1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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 }