51 private final MBeanServer mBeanServer; |
51 private final MBeanServer mBeanServer; |
52 private final Map<String, MBeanResource> mBeanResourceMap = new ConcurrentHashMap<>(); |
52 private final Map<String, MBeanResource> mBeanResourceMap = new ConcurrentHashMap<>(); |
53 private static final int pageSize = 10; |
53 private static final int pageSize = 10; |
54 private static final String pathPrefix = "^/?jmx/servers/[a-zA-Z0-9\\-\\.]+/mbeans"; |
54 private static final String pathPrefix = "^/?jmx/servers/[a-zA-Z0-9\\-\\.]+/mbeans"; |
55 |
55 |
|
56 // Only MXBean or any other MBean that uses types |
|
57 // that have a valid mapper functions |
56 private boolean isMBeanAllowed(ObjectName objName) { |
58 private boolean isMBeanAllowed(ObjectName objName) { |
57 try { |
59 try { |
58 MBeanInfo mInfo = mBeanServer.getMBeanInfo(objName); |
60 MBeanInfo mInfo = mBeanServer.getMBeanInfo(objName); |
|
61 |
|
62 // Return true for MXbean |
|
63 Descriptor desc = mInfo.getDescriptor(); |
|
64 String isMxBean = (String) desc.getFieldValue("mxbean"); |
|
65 if (isMxBean.equalsIgnoreCase("true")) |
|
66 return true; |
|
67 |
|
68 // Check attribute types |
59 MBeanAttributeInfo[] attrsInfo = mInfo.getAttributes(); |
69 MBeanAttributeInfo[] attrsInfo = mInfo.getAttributes(); |
60 for (MBeanAttributeInfo attrInfo : attrsInfo) { |
70 for (MBeanAttributeInfo attrInfo : attrsInfo) { |
61 String type = attrInfo.getType(); |
71 String type = attrInfo.getType(); |
62 if (!JSONMappingFactory.INSTANCE.isTypeMapped(type)) { |
72 if (!JSONMappingFactory.INSTANCE.isTypeMapped(type)) { |
63 return false; |
73 return false; |
64 } |
74 } |
65 } |
75 } |
|
76 |
|
77 // Check operation parameters and return types |
66 MBeanOperationInfo[] operations = mInfo.getOperations(); |
78 MBeanOperationInfo[] operations = mInfo.getOperations(); |
67 for (MBeanOperationInfo opInfo : operations) { |
79 for (MBeanOperationInfo opInfo : operations) { |
68 MBeanParameterInfo[] signature = opInfo.getSignature(); |
80 MBeanParameterInfo[] signature = opInfo.getSignature(); |
69 for (MBeanParameterInfo sig : signature) { |
81 for (MBeanParameterInfo sig : signature) { |
70 if (!JSONMappingFactory.INSTANCE.isTypeMapped(sig.getType())) { |
82 if (!JSONMappingFactory.INSTANCE.isTypeMapped(sig.getType())) { |
111 public MBeanCollectionResource(MBeanServer mBeanServer) { |
124 public MBeanCollectionResource(MBeanServer mBeanServer) { |
112 this.mBeanServer = mBeanServer; |
125 this.mBeanServer = mBeanServer; |
113 allowedMbeans = new ArrayList<>(); |
126 allowedMbeans = new ArrayList<>(); |
114 introspectMBeanTypes(mBeanServer); |
127 introspectMBeanTypes(mBeanServer); |
115 allowedMbeans = new CopyOnWriteArrayList<>(allowedMbeans); |
128 allowedMbeans = new CopyOnWriteArrayList<>(allowedMbeans); |
|
129 |
|
130 // Create a REST handler for each MBean |
116 allowedMbeans.forEach(objectName -> mBeanResourceMap.put(objectName.toString(), |
131 allowedMbeans.forEach(objectName -> mBeanResourceMap.put(objectName.toString(), |
117 new MBeanResource(mBeanServer, objectName))); |
132 new MBeanResource(mBeanServer, objectName))); |
118 } |
133 } |
119 |
134 |
120 @Override |
135 @Override |
134 if (ss.indexOf('/') != -1) { |
149 if (ss.indexOf('/') != -1) { |
135 mBeanName = ss.substring(0, ss.indexOf('/')); |
150 mBeanName = ss.substring(0, ss.indexOf('/')); |
136 } |
151 } |
137 MBeanResource mBeanResource = mBeanResourceMap.get(mBeanName); |
152 MBeanResource mBeanResource = mBeanResourceMap.get(mBeanName); |
138 if (mBeanResource == null) { |
153 if (mBeanResource == null) { |
139 HttpUtil.sendResponse(exchange, new HttpResponse(404, "Not found")); |
154 HttpUtil.sendResponse(exchange, HttpResponse.REQUEST_NOT_FOUND); |
140 return; |
155 return; |
141 } |
156 } |
142 mBeanResource.handle(exchange); |
157 mBeanResource.handle(exchange); |
143 } |
158 } |
144 } |
159 } |
145 } |
160 } |
146 |
161 |
147 @Override |
162 @Override |
148 public HttpResponse doGet(HttpExchange exchange) { |
163 public HttpResponse doGet(HttpExchange exchange) { |
149 // add links |
164 final String path = PlatformRestAdapter.getDomain() |
150 |
165 + exchange.getRequestURI().getPath().replaceAll("/$", ""); |
151 final String path = PlatformRestAdapter.getDomain() + exchange.getRequestURI().getPath().replaceAll("\\/$", ""); |
166 try { |
152 try { |
167 List<ObjectName> filteredMBeans = allowedMbeans; |
153 List<ObjectName> mbeans = allowedMbeans; |
|
154 Map<String, String> queryMap = HttpUtil.getGetRequestQueryMap(exchange); |
168 Map<String, String> queryMap = HttpUtil.getGetRequestQueryMap(exchange); |
155 if (queryMap.containsKey("query")) { |
169 if (queryMap.containsKey("query")) { // Filter based on ObjectName query |
156 Set<ObjectName> queryMBeans = mBeanServer.queryNames(new ObjectName(queryMap.get("query")), null); |
170 Set<ObjectName> queryMBeans = mBeanServer |
157 queryMBeans.retainAll(allowedMbeans); |
171 .queryNames(new ObjectName(queryMap.get("query")), null); |
158 mbeans = new ArrayList<>(queryMBeans); |
172 queryMBeans.retainAll(allowedMbeans); // Intersection of two lists |
159 } |
173 filteredMBeans = new ArrayList<>(queryMBeans); |
160 |
174 } |
161 JSONObject _links = HttpUtil.getPaginationLinks(exchange, mbeans, pageSize); |
175 |
162 List<ObjectName> filteredMBeans = HttpUtil.filterByPage(exchange, mbeans, pageSize); |
176 JSONObject _links = HttpUtil.getPaginationLinks(exchange, filteredMBeans, pageSize); |
|
177 filteredMBeans = HttpUtil.filterByPage(exchange, filteredMBeans, pageSize); |
|
178 |
163 List<Map<String, String>> items = new ArrayList<>(filteredMBeans.size()); |
179 List<Map<String, String>> items = new ArrayList<>(filteredMBeans.size()); |
164 filteredMBeans.forEach(objectName -> { |
180 filteredMBeans.forEach(objectName -> { |
165 Map<String, String> item = new LinkedHashMap<>(2); |
181 Map<String, String> item = new LinkedHashMap<>(2); |
166 item.put("name", objectName.toString()); |
182 item.put("name", objectName.toString()); |
167 String href = path + "/" + objectName.toString(); |
183 String href = path + "/" + objectName.toString(); |
170 items.add(item); |
186 items.add(item); |
171 }); |
187 }); |
172 |
188 |
173 Map<String, String> properties = new HashMap<>(); |
189 Map<String, String> properties = new HashMap<>(); |
174 |
190 |
175 properties.put("mbeanCount", Integer.toString(mbeans.size())); |
191 properties.put("mbeanCount", Integer.toString(filteredMBeans.size())); |
176 |
192 |
177 JSONMapper typeMapper1 = JSONMappingFactory.INSTANCE.getTypeMapper(items); |
193 JSONMapper typeMapper1 = JSONMappingFactory.INSTANCE.getTypeMapper(items); |
178 JSONMapper typeMapper2 = JSONMappingFactory.INSTANCE.getTypeMapper(properties); |
194 JSONMapper typeMapper2 = JSONMappingFactory.INSTANCE.getTypeMapper(properties); |
179 |
195 |
180 JSONElement linkElem = typeMapper1.toJsonValue(items); |
196 JSONElement linkElem = typeMapper1.toJsonValue(items); |
181 JSONElement propElem = typeMapper2.toJsonValue(properties); |
197 JSONElement propElem = typeMapper2.toJsonValue(properties); |
182 JSONObject jobj = new JSONObject(); |
198 JSONObject jobj = new JSONObject(); |
|
199 |
|
200 jobj.putAll((JSONObject) propElem); |
|
201 jobj.put("mbeans", linkElem); |
|
202 |
183 if (_links != null && !_links.isEmpty()) { |
203 if (_links != null && !_links.isEmpty()) { |
184 jobj.put("_links", _links); |
204 jobj.put("_links", _links); |
185 } |
205 } |
186 |
206 return new HttpResponse(jobj.toJsonString()); |
187 jobj.putAll((JSONObject) propElem); |
|
188 jobj.put("items", linkElem); |
|
189 |
|
190 return new HttpResponse(200, jobj.toJsonString()); |
|
191 } catch (JSONMappingException e) { |
207 } catch (JSONMappingException e) { |
192 return new HttpResponse(500, "Internal server error"); |
208 return HttpResponse.SERVER_ERROR; |
193 } catch (UnsupportedEncodingException e) { |
209 } catch (UnsupportedEncodingException e) { |
194 return HttpResponse.SERVER_ERROR; |
210 return HttpResponse.BAD_REQUEST; |
195 } catch (MalformedObjectNameException e) { |
211 } catch (MalformedObjectNameException e) { |
196 return new HttpResponse(HttpResponse.BAD_REQUEST, "Invalid query string"); |
212 return new HttpResponse(HttpResponse.BAD_REQUEST, "Invalid query string"); |
197 } |
213 } |
198 } |
|
199 |
|
200 @Override |
|
201 public HttpResponse doPut(HttpExchange exchange) { |
|
202 return null; |
|
203 } |
214 } |
204 |
215 |
205 @Override |
216 @Override |
206 public HttpResponse doPost(HttpExchange exchange) { |
217 public HttpResponse doPost(HttpExchange exchange) { |
207 String path = exchange.getRequestURI().getPath(); |
218 String path = exchange.getRequestURI().getPath(); |
222 |
233 |
223 JSONObject jsonObject = (JSONObject) jsonElement; |
234 JSONObject jsonObject = (JSONObject) jsonElement; |
224 JSONObject result = new JSONObject(); |
235 JSONObject result = new JSONObject(); |
225 for (String mBeanName : jsonObject.keySet()) { |
236 for (String mBeanName : jsonObject.keySet()) { |
226 MBeanResource mBeanResource = mBeanResourceMap.get(mBeanName); |
237 MBeanResource mBeanResource = mBeanResourceMap.get(mBeanName); |
227 try { |
238 if (mBeanResource != null) { |
228 if (mBeanResource == null) { |
|
229 result.put(mBeanName, "Invalid MBean"); |
|
230 } else { |
|
231 JSONElement element = jsonObject.get(mBeanName); |
239 JSONElement element = jsonObject.get(mBeanName); |
232 if (element instanceof JSONObject) { |
240 if (element instanceof JSONObject) { |
233 JSONElement res = mBeanResource.handleBulkRequest(exchange, (JSONObject) element); |
241 JSONElement res = mBeanResource.handleBulkRequest |
|
242 ((JSONObject) element); |
234 result.put(mBeanName, res); |
243 result.put(mBeanName, res); |
235 } else { |
244 } else { |
236 result.put(mBeanName, "Invalid input"); |
245 result.put(mBeanName, "Invalid input"); |
237 } |
246 } |
238 }} catch (Throwable e) { |
247 } else { |
239 e.printStackTrace(); |
248 result.put(mBeanName, "Invalid MBean"); |
240 } |
249 } |
241 } |
250 } |
242 return new HttpResponse(HttpURLConnection.HTTP_OK, result.toJsonString()); |
251 return new HttpResponse(result.toJsonString()); |
243 } else { |
252 } else { |
244 return HttpResponse.METHOD_NOT_ALLOWED; |
253 return HttpResponse.METHOD_NOT_ALLOWED; |
245 } |
254 } |
246 } catch (ParseException e) { |
255 } catch (ParseException e) { |
247 return new HttpResponse(HttpResponse.BAD_REQUEST, "Invalid JSON String for request body"); |
256 return new HttpResponse(HttpResponse.BAD_REQUEST, "Invalid JSON String for request body"); |
248 } catch (IOException e) { |
257 } catch (IOException e) { |
249 return HttpResponse.BAD_REQUEST; |
258 return HttpResponse.BAD_REQUEST; |
250 } |
259 } |
251 } |
260 } |
252 |
|
253 @Override |
|
254 public HttpResponse doDelete(HttpExchange exchange) { |
|
255 return null; |
|
256 } |
|
257 |
|
258 @Override |
|
259 public HttpResponse doHead(HttpExchange exchange) { |
|
260 return null; |
|
261 } |
|
262 } |
261 } |