# HG changeset patch # User hb # Date 1514366088 -19800 # Node ID a798bdd5299792f1c1aed1f793fa85d679d3d86f # Parent 9721e36abeb08bdd9213850652aca07676e594a0 POST : Attribute update - working POST : Bulk operation for MBean - working Exception to HTTP error Mapping diff -r 9721e36abeb0 -r a798bdd52997 src/java.management.rest/share/classes/com/oracle/jmx/remote/rest/http/HttpResponse.java --- a/src/java.management.rest/share/classes/com/oracle/jmx/remote/rest/http/HttpResponse.java Mon Dec 25 20:42:05 2017 +0530 +++ b/src/java.management.rest/share/classes/com/oracle/jmx/remote/rest/http/HttpResponse.java Wed Dec 27 14:44:48 2017 +0530 @@ -31,6 +31,7 @@ private final int code; private final String message; private final String detail; + private final String body; public HttpResponse(int code, String message) { this(code, message, ""); @@ -40,29 +41,30 @@ this.code = code; this.message = message; this.detail = detail; + + if (code != HttpURLConnection.HTTP_OK) { + JSONObject jobj = new JSONObject(); + jobj.put("status", new JSONPrimitive(code)); + jobj.put("message", new JSONPrimitive(message)); + if (detail != null && !detail.isEmpty()) { + jobj.put("details", new JSONPrimitive(detail)); + } + this.body = jobj.toJsonString(); + } else { + this.body = message; + } } public HttpResponse(HttpResponse response, String detail) { - this.code = response.code; - this.message = response.message; - this.detail = detail; + this(response.code, response.message, detail); } public int getCode() { return code; } - public String getResponse() { - if(code != HttpURLConnection.HTTP_OK) { - JSONObject jobj = new JSONObject(); - jobj.put("status",new JSONPrimitive(code)); - jobj.put("message",new JSONPrimitive(message)); - if(detail != null && !detail.isEmpty()) { - jobj.put("details", new JSONPrimitive(detail)); - } - return jobj.toJsonString(); - } - return message; + public String getBody() { + return body; } static int getHttpErrorCode(Exception ex) { diff -r 9721e36abeb0 -r a798bdd52997 src/java.management.rest/share/classes/com/oracle/jmx/remote/rest/http/HttpUtil.java --- a/src/java.management.rest/share/classes/com/oracle/jmx/remote/rest/http/HttpUtil.java Mon Dec 25 20:42:05 2017 +0530 +++ b/src/java.management.rest/share/classes/com/oracle/jmx/remote/rest/http/HttpUtil.java Wed Dec 27 14:44:48 2017 +0530 @@ -117,7 +117,7 @@ } // Set response headers explicitly - String msg = charset == null ? response.getResponse() : URLEncoder.encode(response.getResponse(), charset); + String msg = charset == null ? response.getBody() : URLEncoder.encode(response.getBody(), charset); byte[] bytes = msg.getBytes(); Headers resHeaders = exchange.getResponseHeaders(); resHeaders.add("Content-Type", "application/json; charset=" + charset); diff -r 9721e36abeb0 -r a798bdd52997 src/java.management.rest/share/classes/com/oracle/jmx/remote/rest/http/JmxRestAdapter.java --- a/src/java.management.rest/share/classes/com/oracle/jmx/remote/rest/http/JmxRestAdapter.java Mon Dec 25 20:42:05 2017 +0530 +++ b/src/java.management.rest/share/classes/com/oracle/jmx/remote/rest/http/JmxRestAdapter.java Wed Dec 27 14:44:48 2017 +0530 @@ -31,9 +31,7 @@ import java.security.AccessControlContext; import java.security.AccessController; import java.security.PrivilegedAction; -import java.util.Arrays; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; /** @@ -165,13 +163,12 @@ } String path = exchange.getRequestURI().getPath(); + // Route request to appropriate resource - if (path.matches("^\\/?jmx\\/servers\\/[a-zA-Z0-9\\\\-\\\\.]+\\/?$")) { + if (path.matches("^/?jmx/servers/[a-zA-Z0-9\\-\\.]+/?$")) { RestResource.super.handle(exchange); - } else if (path.matches("^\\/?jmx\\/servers\\/[a-zA-Z0-9\\-\\.]+\\/mbeans.*")) { + } else if (path.matches("^/?jmx/servers/[a-zA-Z0-9\\-\\.]+/mbeans.*")) { mbeansRes.handle(exchange); -// } else if (path.matches("^\\/?jmx\\/servers\\/[a-zA-Z0-9\\-\\.]+\\/mbeans\\/[^\\/]+\\/?$")) { -// mbeansRes.handle(exchange); } else { HttpUtil.sendResponse(exchange, new HttpResponse(404, "Not found")); } diff -r 9721e36abeb0 -r a798bdd52997 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 Mon Dec 25 20:42:05 2017 +0530 +++ b/src/java.management.rest/share/classes/com/oracle/jmx/remote/rest/http/MBeanCollectionResource.java Wed Dec 27 14:44:48 2017 +0530 @@ -92,12 +92,13 @@ @Override public void handle(HttpExchange exchange) throws IOException { String path = exchange.getRequestURI().getPath(); - if (path.matches("^\\/?jmx\\/servers\\/[a-zA-Z0-9\\-\\.]+\\/mbeans\\/?$")) { + String pathPrefix = "^/?jmx/servers/[a-zA-Z0-9\\-\\.]+/mbeans"; + if (path.matches(pathPrefix + "/?$")) { RestResource.super.handle(exchange); - } else if (path.matches("^\\/?jmx\\/servers\\/[a-zA-Z0-9\\-\\.]+\\/mbeans\\/[^\\/]+\\/?.*")) { + } else if (path.matches(pathPrefix + "/[^/]+/?.*")) { // Extract mbean name // Forward the request to its corresponding rest resource - Pattern mbeans = Pattern.compile("^\\/?jmx\\/servers\\/[a-zA-Z0-9\\-\\.]+\\/mbeans\\/"); + Pattern mbeans = Pattern.compile(pathPrefix + "/"); Matcher matcher = mbeans.matcher(path); if (matcher.find()) { diff -r 9721e36abeb0 -r a798bdd52997 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 Mon Dec 25 20:42:05 2017 +0530 +++ b/src/java.management.rest/share/classes/com/oracle/jmx/remote/rest/http/MBeanResource.java Wed Dec 27 14:44:48 2017 +0530 @@ -4,15 +4,24 @@ import com.oracle.jmx.remote.rest.json.JSONElement; import com.oracle.jmx.remote.rest.json.JSONObject; import com.oracle.jmx.remote.rest.json.JSONPrimitive; +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.JSONDataException; import com.oracle.jmx.remote.rest.mapper.JSONMapper; import com.oracle.jmx.remote.rest.mapper.JSONMappingException; import com.oracle.jmx.remote.rest.mapper.JSONMappingFactory; import com.sun.net.httpserver.HttpExchange; import javax.management.*; +import javax.management.openmbean.OpenMBeanAttributeInfo; +import javax.management.openmbean.OpenMBeanParameterInfo; +import javax.management.openmbean.OpenType; import javax.management.remote.rest.PlatformRestAdapter; import java.io.IOException; +import java.net.HttpURLConnection; import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import static javax.management.MBeanOperationInfo.*; @@ -20,6 +29,21 @@ private final ObjectName objectName; private final MBeanServer mBeanServer; + private static final String pathPrefix = "^/?jmx/servers/[^/]+/mbeans/[^/]+"; + + private final static Map> primitiveToObject = new HashMap<>(); + + static { + primitiveToObject.put("int", Integer.TYPE); + primitiveToObject.put("long", Long.TYPE); + primitiveToObject.put("double", Double.TYPE); + primitiveToObject.put("float", Float.TYPE); + primitiveToObject.put("boolean", Boolean.TYPE); + primitiveToObject.put("char", Character.TYPE); + primitiveToObject.put("byte", Byte.TYPE); + primitiveToObject.put("void", Void.TYPE); + primitiveToObject.put("short", Short.TYPE); + } public MBeanResource(MBeanServer mBeanServer, ObjectName objectName) { this.mBeanServer = mBeanServer; @@ -171,6 +195,29 @@ return jobj2; } + private Map getAttributes(String[] attrs) throws IntrospectionException, + InstanceNotFoundException, ReflectionException, AttributeNotFoundException, MBeanException { + Map result = new LinkedHashMap<>(); + if (attrs.length == 1) { + result.put(attrs[0], mBeanServer.getAttribute(objectName, attrs[0])); + } 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())); + } + } + return result; + } + private Map getAllAttributes() throws IntrospectionException, InstanceNotFoundException, ReflectionException, AttributeNotFoundException, MBeanException { Map result = new HashMap<>(); @@ -206,6 +253,166 @@ return result; } + private Map setAttributes(JSONObject attrMap) throws IntrospectionException, + InstanceNotFoundException, ReflectionException, JSONDataException, ClassNotFoundException, MBeanException { + if (attrMap == null || attrMap.isEmpty()) { + throw new JSONDataException("Null arguments for set attribute"); + } + Map result = new HashMap<>(); + for (String attrName : attrMap.keySet()) { + MBeanInfo mBeanInfo = mBeanServer.getMBeanInfo(objectName); + MBeanAttributeInfo attrInfo = Arrays.stream(mBeanInfo.getAttributes()).filter(a -> a.getName().equals(attrName)).findFirst().orElse(null); + if (attrInfo == null) { + result.put(attrName, ""); + } else if (!attrInfo.isWritable()) { + result.put(attrName, ""); + } else { + JSONMapper mapper; + if (attrInfo instanceof OpenMBeanAttributeInfo) { + OpenType type = ((OpenMBeanAttributeInfo) attrInfo).getOpenType(); + mapper = JSONMappingFactory.INSTANCE.getTypeMapper(type); + } else { + Class inputCls = primitiveToObject.get(attrInfo.getType()); + try { + if (inputCls == null) { + inputCls = Class.forName(attrInfo.getType()); + } + } catch (ClassNotFoundException | ClassCastException ex) { + throw new IllegalArgumentException("Invalid parameters : " + attrMap.get(attrName).toJsonString() + " cannot be mapped to : " + attrInfo.getType()); + } + mapper = JSONMappingFactory.INSTANCE.getTypeMapper(inputCls); + } + try { + Object attrValue = mapper.toJavaObject(attrMap.get(attrName)); + Attribute attrObj = new Attribute(attrName, attrValue); + mBeanServer.setAttribute(objectName, attrObj); + result.put(attrName, "success"); + } catch (InvalidAttributeValueException | JSONDataException e) { + result.put(attrName, ""); + } catch (AttributeNotFoundException e) { + result.put(attrName, ""); + } + } + } + return result; + } + + private Object mapJsonToType(JSONElement jsonElement, MBeanParameterInfo type) { + if (type instanceof OpenMBeanParameterInfo) { + OpenType openType = ((OpenMBeanParameterInfo) type).getOpenType(); + JSONMapper typeMapper = JSONMappingFactory.INSTANCE.getTypeMapper(openType); + try { + return typeMapper.toJavaObject(jsonElement); + } catch (JSONDataException ex) { + throw new IllegalArgumentException("Invalid JSON String : " + jsonElement.toJsonString() + " for arguments"); + } + } else { + Class inputCls = primitiveToObject.get(type.getType()); + try { + if (inputCls == null) { + inputCls = Class.forName(type.getType()); + } + } catch (ClassNotFoundException | ClassCastException ex) { + throw new IllegalArgumentException("Invalid parameters : " + jsonElement.toJsonString() + " cannot be mapped to : " + type.getType()); + } + JSONMapper typeMapper = JSONMappingFactory.INSTANCE.getTypeMapper(inputCls); + if (typeMapper == null) { + throw new IllegalArgumentException("Invalid parameters : " + jsonElement.toJsonString() + " cannot be mapped to : " + type.getType()); + } + try { + return typeMapper.toJavaObject(jsonElement); + } catch (JSONDataException ex) { + throw new IllegalArgumentException("Invalid JSON String : " + jsonElement.toJsonString() + " for arguments"); + } + } + } + + private Map getParameters(Map jsonValues, Map typeMap) { + if (jsonValues.size() != typeMap.size()) { + throw new IllegalArgumentException("Invalid parameters : expected - " + typeMap.size() + " parameters, got - " + jsonValues.size()); + } + if(!jsonValues.keySet().equals(typeMap.keySet())) { + throw new IllegalArgumentException("Invalid parameters - expected : " + Arrays.toString(typeMap.keySet().toArray())); + } + Map parameters = new LinkedHashMap<>(); + if (typeMap.size() == 0 && jsonValues.isEmpty()) { + return parameters; + } + for (String name : typeMap.keySet()) { + MBeanParameterInfo type = typeMap.get(name); + JSONElement jsonVal = jsonValues.get(name); + Object obj = mapJsonToType(jsonVal, type); + parameters.put(name, obj); + } + return parameters; + } + + private JSONElement execOperation(String opstr, JSONObject params) + throws MBeanException, IntrospectionException, ReflectionException, InstanceNotFoundException { + if (params == null) { + params = new JSONObject(); + } + MBeanInfo mBeanInfo; + try { + mBeanInfo = mBeanServer.getMBeanInfo(objectName); + } catch (InstanceNotFoundException ex) { + throw new IllegalArgumentException("MBean does not exist"); + } + + MBeanOperationInfo[] opinfos = Arrays.stream(mBeanInfo.getOperations()). + filter(a -> a.getName().equals(opstr)).toArray(MBeanOperationInfo[]::new); + + if (opinfos.length == 0) { + throw new IllegalArgumentException("Invalid Operation String"); + } + + String[] signature = null; + Object[] parameters = null; + + if (opinfos.length == 1) { + MBeanParameterInfo[] sig = opinfos[0].getSignature(); + Map typeMap = new LinkedHashMap<>(); + Arrays.stream(sig).forEach(e -> typeMap.put(e.getName(), e)); + parameters = getParameters(params, typeMap).values().toArray(); + signature = Arrays.asList(sig).stream().map(a -> a.getType()).toArray(a -> new String[a]); + } else if (opinfos.length > 1) { + IllegalArgumentException exception = null; + for (MBeanOperationInfo opInfo : opinfos) { + MBeanParameterInfo[] sig = opInfo.getSignature(); + try { + Map typeMap = new LinkedHashMap<>(); + Arrays.stream(sig).forEach(e -> typeMap.put(e.getName(), e)); + parameters = getParameters(params, typeMap).values().toArray(); + signature = Arrays.asList(sig).stream().map(a -> a.getType()).toArray(a -> new String[a]); + exception = null; + break; + } catch (IllegalArgumentException ex) { + exception = ex; + } + } + if (exception != null) { + throw exception; + } + } + + Object invoke = null; + try { + invoke = mBeanServer.invoke(objectName, opstr, parameters, signature); + if (invoke != null) { + JSONMapper typeMapper = JSONMappingFactory.INSTANCE.getTypeMapper(invoke); + if (typeMapper != null) { + return typeMapper.toJsonValue(invoke); + } else { + return new JSONPrimitive(""); + } + } else { + return new JSONPrimitive("void"); + } + } catch (JSONMappingException e) { + return new JSONPrimitive(""); + } + } + private HttpResponse doMBeanInfo(HttpExchange exchange) { try { JSONObject mBeanInfo = getMBeanInfo(mBeanServer, objectName); @@ -222,8 +429,11 @@ @Override public void handle(HttpExchange exchange) throws IOException { String path = exchange.getRequestURI().getPath(); - if (path.matches("^\\/?jmx\\/servers\\/[a-zA-Z0-9\\-\\.]+\\/mbeans\\/[^\\/]+\\/?$") || - path.matches("^\\/?jmx\\/servers\\/[a-zA-Z0-9\\-\\.]+\\/mbeans\\/[^\\/]+\\/info$")) { + if (path.matches(pathPrefix + "/?$")) { + RestResource.super.handle(exchange); + } else if (path.matches(pathPrefix + "/info$") && exchange.getRequestMethod().equalsIgnoreCase("GET")) { + RestResource.super.handle(exchange); + } else if (path.matches(pathPrefix + "/[^/]+/?$") && exchange.getRequestMethod().equalsIgnoreCase("POST")) { RestResource.super.handle(exchange); } else { HttpUtil.sendResponse(exchange, new HttpResponse(404, "Not found")); @@ -232,7 +442,7 @@ @Override public HttpResponse doGet(HttpExchange exchange) { - if(exchange.getRequestURI().getPath().endsWith("info")) { + if (exchange.getRequestURI().getPath().endsWith("info")) { return doMBeanInfo(exchange); } String path = PlatformRestAdapter.getAuthority() + exchange.getRequestURI().getPath().replaceAll("\\/$", ""); @@ -241,7 +451,7 @@ try { Map allAttributes = getAllAttributes(); Map _links = new LinkedHashMap<>(); - _links.put("info",HttpUtil.escapeUrl(info)); + _links.put("info", HttpUtil.escapeUrl(info)); MBeanOperationInfo[] opInfo = mBeanServer.getMBeanInfo(objectName).getOperations(); JSONArray jarr = new JSONArray(); @@ -263,14 +473,14 @@ } JSONMapper typeMapper = JSONMappingFactory.INSTANCE.getTypeMapper(allAttributes); - if(typeMapper != null) { + if (typeMapper != null) { JSONElement jsonElement1 = typeMapper.toJsonValue(allAttributes); JSONElement jsonElement2 = typeMapper.toJsonValue(_links); JSONObject jobj = new JSONObject(); - jobj.put("attributes",jsonElement1); - jobj.put("operations",jarr); - jobj.put("_links",jsonElement2); + jobj.put("attributes", jsonElement1); + jobj.put("operations", jarr); + jobj.put("_links", jsonElement2); return new HttpResponse(200, jobj.toJsonString()); } else { return new HttpResponse(HttpResponse.SERVER_ERROR, "Unable to find JSONMapper"); @@ -289,13 +499,194 @@ } } + /* + HTTP POST for this MBean's URL allows setting of attributes and execution of operations. + POST request body can follow one of the below formats + 1. { name : value} + Set a single attribute + 2. { name1 : value1, name2 : value2 } + Sets multiple attributes + 3. {attributes : {read : [name]} , {write : {name : value}}, operations : {op_name : {param_name:name, param_value:value}}} + This bulk operation request sets multiple attributes and executes multiple + operations on the MBean. + */ @Override - public HttpResponse doPut(HttpExchange exchange) { - return null; + public HttpResponse doPost(HttpExchange exchange) { + 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; + + if (jsonObject.keySet().contains("attributes") | jsonObject.keySet().contains("operations")) { + return handleBulkRequest(exchange, jsonObject); + } else { + Map stringObjectMap = setAttributes(jsonObject); + JSONMapper typeMapper = JSONMappingFactory.INSTANCE.getTypeMapper(stringObjectMap); + if (typeMapper != null) { + return new HttpResponse(HttpURLConnection.HTTP_OK, typeMapper.toJsonValue(stringObjectMap).toJsonString()); + } else { + return new HttpResponse(HttpResponse.SERVER_ERROR, "Unable to find JSON Mapper"); + } + } + } else if (path.matches(pathPrefix + "/[^/]+/?$")) { // POST to MBeanOperation + Matcher matcher = Pattern.compile(pathPrefix + "/").matcher(path); + String operation; + if (matcher.find()) { + String ss = path.substring(matcher.end()); + operation = ss; + } else { + return HttpResponse.BAD_REQUEST; + } + + reqBody = HttpUtil.readRequestBody(exchange); + JSONElement result; + if (reqBody == null || reqBody.isEmpty()) { // No Parameters + result = execOperation(operation, null); + } else { + JSONParser parser = new JSONParser(reqBody); + JSONElement jsonElement = parser.parse(); + if (!(jsonElement instanceof JSONObject)) { + return new HttpResponse(HttpResponse.BAD_REQUEST, + "Invalid parameters : [" + reqBody + "] for operation - " + operation); + } + result = execOperation(operation, (JSONObject) jsonElement); + } + return new HttpResponse(HttpURLConnection.HTTP_OK, result.toJsonString()); + } else { + return HttpResponse.REQUEST_NOT_FOUND; + } + } catch (InstanceNotFoundException e) { + // Should never happen + } catch (ClassNotFoundException | 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)); + } catch (IllegalArgumentException e) { + return new HttpResponse(HttpResponse.BAD_REQUEST, e.getMessage()); + } catch (Exception e) { + return new HttpResponse(HttpResponse.SERVER_ERROR, HttpResponse.getErrorMessage(e)); + } + return HttpResponse.REQUEST_NOT_FOUND; + } + + private HttpResponse handleBulkRequest(HttpExchange exchange, JSONObject reqObject) { + try { + 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); + } + + // 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; + } + 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); + 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); + } + } + } + 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)); + } + return HttpResponse.REQUEST_NOT_FOUND; + } + + private String[] getStrings(JSONArray jsonArray) throws JSONDataException { + List attributes = new ArrayList<>(); + for (JSONElement element : jsonArray) { + if (element instanceof JSONPrimitive && ((JSONPrimitive) element).getValue() instanceof String) { + JSONPrimitive val = (JSONPrimitive) element; + attributes.add((String) val.getValue()); + } else throw new JSONDataException("Expecting String, got " + element.toJsonString()); + } + return attributes.toArray(new String[0]); } @Override - public HttpResponse doPost(HttpExchange exchange) { + public HttpResponse doPut(HttpExchange exchange) { return null; } diff -r 9721e36abeb0 -r a798bdd52997 src/java.management.rest/share/classes/com/oracle/jmx/remote/rest/http/RestResource.java --- a/src/java.management.rest/share/classes/com/oracle/jmx/remote/rest/http/RestResource.java Mon Dec 25 20:42:05 2017 +0530 +++ b/src/java.management.rest/share/classes/com/oracle/jmx/remote/rest/http/RestResource.java Wed Dec 27 14:44:48 2017 +0530 @@ -7,6 +7,7 @@ import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; + import java.io.IOException; /** @@ -36,7 +37,7 @@ } HttpUtil.sendResponse(exchange,httpResponse); } - + public HttpResponse doGet(HttpExchange exchange); public HttpResponse doPut(HttpExchange exchange); public HttpResponse doPost(HttpExchange exchange); diff -r 9721e36abeb0 -r a798bdd52997 src/java.management.rest/share/classes/javax/management/remote/rest/PlatformRestAdapter.java --- a/src/java.management.rest/share/classes/javax/management/remote/rest/PlatformRestAdapter.java Mon Dec 25 20:42:05 2017 +0530 +++ b/src/java.management.rest/share/classes/javax/management/remote/rest/PlatformRestAdapter.java Wed Dec 27 14:44:48 2017 +0530 @@ -226,14 +226,14 @@ /** * Default values for JMX configuration properties. */ - public static interface DefaultValues { + static interface DefaultValues { public static final String PORT = "0"; public static final String CONFIG_FILE_NAME = "management.properties"; - public static final String USE_SSL = "true"; + public static final String USE_SSL = "false"; public static final String USE_LOCAL_ONLY = "true"; public static final String USE_REGISTRY_SSL = "false"; - public static final String USE_AUTHENTICATION = "true"; + public static final String USE_AUTHENTICATION = "false"; public static final String PASSWORD_FILE_NAME = "jmxremote.password"; public static final String ACCESS_FILE_NAME = "jmxremote.access"; public static final String SSL_NEED_CLIENT_AUTH = "false"; diff -r 9721e36abeb0 -r a798bdd52997 test/jdk/javax/management/remote/rest/RunRestAdapter.java --- a/test/jdk/javax/management/remote/rest/RunRestAdapter.java Mon Dec 25 20:42:05 2017 +0530 +++ b/test/jdk/javax/management/remote/rest/RunRestAdapter.java Wed Dec 27 14:44:48 2017 +0530 @@ -68,7 +68,7 @@ Properties props = new Properties(); props.setProperty("com.sun.management.jmxremote.ssl", "true"); props.setProperty("com.sun.management.jmxremote.ssl.config.file", sslAgentConfig); - props.setProperty("com.sun.management.jmxremote.authenticate", "false"); + props.setProperty("com.sun.management.jmxremote.authenticate", "true"); props.setProperty("com.sun.management.jmxremote.rest.port", "8686"); try (BufferedWriter writer = new BufferedWriter(new FileWriter(fileName))) {