# HG changeset patch # User hb # Date 1514370953 -19800 # Node ID e8d4ccaf68776c3b0653268f85631ae21d0a3419 # Parent a798bdd5299792f1c1aed1f793fa85d679d3d86f Bulk operation at MBeanServer level diff -r a798bdd52997 -r e8d4ccaf6877 src/java.management.rest/share/classes/com/oracle/jmx/remote/rest/http/MBeanCollectionResource.java --- a/src/java.management.rest/share/classes/com/oracle/jmx/remote/rest/http/MBeanCollectionResource.java Wed Dec 27 14:44:48 2017 +0530 +++ b/src/java.management.rest/share/classes/com/oracle/jmx/remote/rest/http/MBeanCollectionResource.java Wed Dec 27 16:05:53 2017 +0530 @@ -2,6 +2,8 @@ import com.oracle.jmx.remote.rest.json.JSONElement; import com.oracle.jmx.remote.rest.json.JSONObject; +import com.oracle.jmx.remote.rest.json.parser.JSONParser; +import com.oracle.jmx.remote.rest.json.parser.ParseException; import com.oracle.jmx.remote.rest.mapper.JSONMapper; import com.oracle.jmx.remote.rest.mapper.JSONMappingException; import com.oracle.jmx.remote.rest.mapper.JSONMappingFactory; @@ -11,10 +13,10 @@ import javax.management.remote.rest.PlatformRestAdapter; import java.io.IOException; import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.CopyOnWriteArraySet; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -24,6 +26,7 @@ private final MBeanServer mBeanServer; private final Map mBeanResourceMap = new ConcurrentHashMap<>(); private static final int pageSize = 10; + private static final String pathPrefix = "^/?jmx/servers/[a-zA-Z0-9\\-\\.]+/mbeans"; private boolean isMBeanAllowed(ObjectName objName) { try { @@ -92,7 +95,6 @@ @Override public void handle(HttpExchange exchange) throws IOException { String path = exchange.getRequestURI().getPath(); - String pathPrefix = "^/?jmx/servers/[a-zA-Z0-9\\-\\.]+/mbeans"; if (path.matches(pathPrefix + "/?$")) { RestResource.super.handle(exchange); } else if (path.matches(pathPrefix + "/[^/]+/?.*")) { @@ -125,8 +127,8 @@ try { List mbeans = allowedMbeans; Map queryMap = HttpUtil.getGetRequestQueryMap(exchange); - if(queryMap.containsKey("query")) { - Set queryMBeans = mBeanServer.queryNames(new ObjectName(queryMap.get("query")),null); + if (queryMap.containsKey("query")) { + Set queryMBeans = mBeanServer.queryNames(new ObjectName(queryMap.get("query")), null); queryMBeans.retainAll(allowedMbeans); mbeans = new ArrayList<>(queryMBeans); } @@ -153,8 +155,8 @@ JSONElement linkElem = typeMapper1.toJsonValue(items); JSONElement propElem = typeMapper2.toJsonValue(properties); JSONObject jobj = new JSONObject(); - if(_links != null && !_links.isEmpty()) { - jobj.put("_links",_links); + if (_links != null && !_links.isEmpty()) { + jobj.put("_links", _links); } jobj.putAll((JSONObject) propElem); @@ -177,7 +179,50 @@ @Override public HttpResponse doPost(HttpExchange exchange) { - return null; + String path = exchange.getRequestURI().getPath(); + String reqBody = null; + try { + if (path.matches(pathPrefix + "/?$")) { // POST to current URL + reqBody = HttpUtil.readRequestBody(exchange); + if (reqBody == null || reqBody.isEmpty()) { // No Parameters + return HttpResponse.BAD_REQUEST; + } + + JSONParser parser = new JSONParser(reqBody); + JSONElement jsonElement = parser.parse(); + if (!(jsonElement instanceof JSONObject)) { + return new HttpResponse(HttpResponse.BAD_REQUEST, + "Invalid parameters : [" + reqBody + "]"); + } + + JSONObject jsonObject = (JSONObject) jsonElement; + JSONObject result = new JSONObject(); + for (String mBeanName : jsonObject.keySet()) { + MBeanResource mBeanResource = mBeanResourceMap.get(mBeanName); + try { + if (mBeanResource == null) { + result.put(mBeanName, "Invalid MBean"); + } else { + JSONElement element = jsonObject.get(mBeanName); + if (element instanceof JSONObject) { + JSONElement res = mBeanResource.handleBulkRequest(exchange, (JSONObject) element); + result.put(mBeanName, res); + } else { + result.put(mBeanName, "Invalid input"); + } + }} catch (Throwable e) { + e.printStackTrace(); + } + } + return new HttpResponse(HttpURLConnection.HTTP_OK, result.toJsonString()); + } else { + return HttpResponse.METHOD_NOT_ALLOWED; + } + } catch (ParseException e) { + return new HttpResponse(HttpResponse.BAD_REQUEST, "Invalid JSON String for request body"); + } catch (IOException e) { + return HttpResponse.BAD_REQUEST; + } } @Override diff -r a798bdd52997 -r e8d4ccaf6877 src/java.management.rest/share/classes/com/oracle/jmx/remote/rest/http/MBeanResource.java --- a/src/java.management.rest/share/classes/com/oracle/jmx/remote/rest/http/MBeanResource.java Wed Dec 27 14:44:48 2017 +0530 +++ b/src/java.management.rest/share/classes/com/oracle/jmx/remote/rest/http/MBeanResource.java Wed Dec 27 16:05:53 2017 +0530 @@ -195,26 +195,26 @@ return jobj2; } - private Map getAttributes(String[] attrs) throws IntrospectionException, - InstanceNotFoundException, ReflectionException, AttributeNotFoundException, MBeanException { + private Map getAttributes(String[] attrs) throws InstanceNotFoundException, + ReflectionException { Map result = new LinkedHashMap<>(); - if (attrs.length == 1) { - result.put(attrs[0], mBeanServer.getAttribute(objectName, attrs[0])); + if (attrs == null || attrs.length == 0) { + return result; + } + AttributeList attrVals = mBeanServer.getAttributes(objectName, attrs); + if (attrVals.size() != attrs.length) { + List missingAttrs = new ArrayList<>(Arrays.asList(attrs)); + for (Attribute a : attrVals.asList()) { + missingAttrs.remove(a.getName()); + result.put(a.getName(), a.getValue()); + } + for (String attr : missingAttrs) { + result.put(attr, "< Error: No such attribute >"); + } } else { - AttributeList attrVals = mBeanServer.getAttributes(objectName, attrs); - if (attrVals.size() != attrs.length) { - List missingAttrs = new ArrayList<>(Arrays.asList(attrs)); - for (Attribute a : attrVals.asList()) { - missingAttrs.remove(a.getName()); - result.put(a.getName(), a.getValue()); - } - for (String attr : missingAttrs) { - result.put(attr, "< Error: No such attribute >"); - } - } else { - attrVals.asList().forEach((a) -> result.put(a.getName(), a.getValue())); - } + attrVals.asList().forEach((a) -> result.put(a.getName(), a.getValue())); } + return result; } @@ -253,8 +253,8 @@ return result; } - private Map setAttributes(JSONObject attrMap) throws IntrospectionException, - InstanceNotFoundException, ReflectionException, JSONDataException, ClassNotFoundException, MBeanException { + private Map setAttributes(JSONObject attrMap) throws JSONDataException, + IntrospectionException, InstanceNotFoundException, ReflectionException { if (attrMap == null || attrMap.isEmpty()) { throw new JSONDataException("Null arguments for set attribute"); } @@ -291,6 +291,8 @@ result.put(attrName, ""); } catch (AttributeNotFoundException e) { result.put(attrName, ""); + } catch (ReflectionException | InstanceNotFoundException | MBeanException e) { + result.put(attrName, ""); } } } @@ -331,7 +333,7 @@ if (jsonValues.size() != typeMap.size()) { throw new IllegalArgumentException("Invalid parameters : expected - " + typeMap.size() + " parameters, got - " + jsonValues.size()); } - if(!jsonValues.keySet().equals(typeMap.keySet())) { + if (!jsonValues.keySet().equals(typeMap.keySet())) { throw new IllegalArgumentException("Invalid parameters - expected : " + Arrays.toString(typeMap.keySet().toArray())); } Map parameters = new LinkedHashMap<>(); @@ -531,7 +533,7 @@ JSONObject jsonObject = (JSONObject) jsonElement; if (jsonObject.keySet().contains("attributes") | jsonObject.keySet().contains("operations")) { - return handleBulkRequest(exchange, jsonObject); + return new HttpResponse(HttpURLConnection.HTTP_OK, handleBulkRequest(exchange, jsonObject).toJsonString()); } else { Map stringObjectMap = setAttributes(jsonObject); JSONMapper typeMapper = JSONMappingFactory.INSTANCE.getTypeMapper(stringObjectMap); @@ -570,7 +572,7 @@ } } catch (InstanceNotFoundException e) { // Should never happen - } catch (ClassNotFoundException | JSONDataException | ParseException e) { + } catch (JSONDataException | ParseException e) { return new HttpResponse(HttpURLConnection.HTTP_BAD_REQUEST, "Invalid JSON : " + reqBody, e.getMessage()); } catch (IntrospectionException | JSONMappingException | MBeanException | ReflectionException | IOException e) { return new HttpResponse(HttpResponse.SERVER_ERROR, HttpResponse.getErrorMessage(e)); @@ -582,96 +584,97 @@ return HttpResponse.REQUEST_NOT_FOUND; } - private HttpResponse handleBulkRequest(HttpExchange exchange, JSONObject reqObject) { - try { - JSONObject result = new JSONObject(); + public JSONElement handleBulkRequest(HttpExchange exchange, JSONObject reqObject) { + + JSONObject result = new JSONObject(); - do { - // Handle attributes - JSONElement element = reqObject.get("attributes"); - if (element != null && !(element instanceof JSONObject)) // input validation - break; - if (element != null && element instanceof JSONObject) { - JSONObject attrInfo = (JSONObject) element; - JSONObject attrNode = new JSONObject(); - // atleast one of get/set must be present - if (attrInfo.get("get") == null && attrInfo.get("set") == null) - break; - // Read attributes - JSONElement read = attrInfo.get("get"); - if (read != null && !(read instanceof JSONArray)) - break; - if (read != null && read instanceof JSONArray) { - JSONArray jattrs = (JSONArray) read; - String[] attributes = getStrings(jattrs); - Map attrRead = getAttributes(attributes); - JSONMapper typeMapper = JSONMappingFactory.INSTANCE.getTypeMapper(attrRead); - JSONElement jAttrRead = typeMapper.toJsonValue(attrRead); - attrNode.put("get", jAttrRead); - } - - // Write attributes - JSONElement write = attrInfo.get("set"); - - if (write != null && !(write instanceof JSONObject)) - break; - - if (write != null && write instanceof JSONObject) { - JSONObject jattrs = (JSONObject) write; - Map attrMap = setAttributes(jattrs); - JSONMapper typeMapper = JSONMappingFactory.INSTANCE.getTypeMapper(attrMap); - JSONElement jAttrRead = typeMapper.toJsonValue(attrMap); - attrNode.put("set", jAttrRead); - } - result.put("attributes", attrNode); + // Handle attributes + JSONElement element = reqObject.get("attributes"); + if (element != null && element instanceof JSONObject) { + JSONObject attrInfo = (JSONObject) element; + JSONObject attrNode = new JSONObject(); + // Read attributes + JSONElement read = attrInfo.get("get"); + if (read != null && read instanceof JSONArray) { + JSONArray jattrs = (JSONArray) read; + JSONElement jAttrRead; + Map attrRead = null; + try { + String[] attributes = getStrings(jattrs); + attrRead = getAttributes(attributes); + JSONMapper typeMapper = JSONMappingFactory.INSTANCE.getTypeMapper(attrRead); + jAttrRead = typeMapper.toJsonValue(attrRead); + } catch (InstanceNotFoundException | ReflectionException | JSONMappingException e) { + jAttrRead = new JSONPrimitive(""); + } catch (JSONDataException e) { + jAttrRead = new JSONPrimitive("Invalid JSON : " + read.toJsonString()); } - // Execute operations - element = reqObject.get("operations"); - if (element != null) { - JSONArray operationList; - if (element instanceof JSONPrimitive // Single no-arg operation - || element instanceof JSONObject) { // single/mulitple operations - operationList = new JSONArray(); - operationList.add(element); - } else if (element instanceof JSONArray) { // List of no-arg/with-arg operation - operationList = (JSONArray) element; - } else { - // Should never happen - return HttpResponse.BAD_REQUEST; + attrNode.put("get", jAttrRead); + } + + // Write attributes + JSONElement write = attrInfo.get("set"); + JSONElement jAttrRead; + if (write != null && write instanceof JSONObject) { + JSONObject jattrs = (JSONObject) write; + try { + Map attrMap = setAttributes(jattrs); + JSONMapper typeMapper = JSONMappingFactory.INSTANCE.getTypeMapper(attrMap); + jAttrRead = typeMapper.toJsonValue(attrMap); + } catch (JSONDataException ex) { + jAttrRead = new JSONPrimitive("Invalid JSON : " + write.toJsonString()); + } catch (JSONMappingException | IntrospectionException | InstanceNotFoundException | ReflectionException e) { + jAttrRead = new JSONPrimitive(""); + } + attrNode.put("set", jAttrRead); + } + result.put("attributes", attrNode); + } + + // Execute operations + element = reqObject.get("operations"); + if (element != null) { + JSONArray operationList; + if (element instanceof JSONPrimitive // Single no-arg operation + || element instanceof JSONObject) { // single/mulitple operations + operationList = new JSONArray(); + operationList.add(element); + } else if (element instanceof JSONArray) { // List of no-arg/with-arg operation + operationList = (JSONArray) element; + } else { + operationList = new JSONArray(); + } + JSONObject opResult = new JSONObject(); + for (JSONElement elem : operationList) { + if (elem instanceof JSONPrimitive + && ((JSONPrimitive) elem).getValue() instanceof String) { // no-arg operation + String opName = (String) ((JSONPrimitive) elem).getValue(); + try { + JSONElement obj = execOperation(opName, null); + opResult.put(opName, obj); + } catch (IllegalArgumentException e) { + opResult.put(opName, e.getMessage()); + } catch (IntrospectionException | InstanceNotFoundException | MBeanException | ReflectionException e) { + opResult.put(opName, ""); } - JSONObject opResult = new JSONObject(); - for (JSONElement elem : operationList) { - if (elem instanceof JSONPrimitive - && ((JSONPrimitive) elem).getValue() instanceof String) { // no-arg operation - String opName = (String) ((JSONPrimitive) elem).getValue(); - JSONElement obj = execOperation(opName, null); + } else if (elem instanceof JSONObject) { + Set opNames = ((JSONObject) element).keySet(); + for (String opName : opNames) { + try { + JSONElement obj = execOperation(opName, (JSONObject) ((JSONObject) element).get(opName)); opResult.put(opName, obj); - } else if (elem instanceof JSONObject) { - Set opNames = ((JSONObject) element).keySet(); - for (String opName : opNames) { - JSONElement obj = execOperation(opName, (JSONObject) ((JSONObject) element).get(opName)); - opResult.put(opName, obj); - } + } catch (IllegalArgumentException e) { + opResult.put(opName, e.getMessage()); + } catch (IntrospectionException | InstanceNotFoundException | MBeanException | ReflectionException e) { + opResult.put(opName, ""); } } - result.put("operations", opResult); } - return new HttpResponse(HttpURLConnection.HTTP_OK, result.toJsonString()); - } while (false); - throw new JSONDataException("Invalid request body : " + reqObject.toJsonString()); - } catch (InstanceNotFoundException e) { - // Should never happen - } catch (ClassNotFoundException | JSONDataException e) { - return new HttpResponse(HttpResponse.BAD_REQUEST, "Invalid JSON : " + e.getMessage()); - } catch (IntrospectionException | JSONMappingException | MBeanException | ReflectionException e) { - return new HttpResponse(HttpResponse.SERVER_ERROR, HttpResponse.getErrorMessage(e)); - } catch (IllegalArgumentException e) { - return new HttpResponse(HttpResponse.BAD_REQUEST, e.getMessage()); - } catch (Exception e) { - return new HttpResponse(HttpResponse.SERVER_ERROR, HttpResponse.getErrorMessage(e)); + } + result.put("operations", opResult); } - return HttpResponse.REQUEST_NOT_FOUND; + return result; } private String[] getStrings(JSONArray jsonArray) throws JSONDataException {