Code cleanup - MBeanColl*Resource, MBeanResource jmx-rest-api
authorhb
Thu, 28 Dec 2017 20:05:03 +0530
branchjmx-rest-api
changeset 56000 054866e5113c
parent 55999 2db04c2274fd
child 56001 95c0323f0c1a
Code cleanup - MBeanColl*Resource, MBeanResource
src/java.management.rest/share/classes/com/oracle/jmx/remote/rest/http/MBeanCollectionResource.java
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/MBeanCollectionResource.java	Thu Dec 28 14:43:34 2017 +0530
+++ b/src/java.management.rest/share/classes/com/oracle/jmx/remote/rest/http/MBeanCollectionResource.java	Thu Dec 28 20:05:03 2017 +0530
@@ -53,9 +53,19 @@
     private static final int pageSize = 10;
     private static final String pathPrefix = "^/?jmx/servers/[a-zA-Z0-9\\-\\.]+/mbeans";
 
+    // Only MXBean or any other MBean that uses types
+    // that have a valid mapper functions
     private boolean isMBeanAllowed(ObjectName objName) {
         try {
             MBeanInfo mInfo = mBeanServer.getMBeanInfo(objName);
+
+            // Return true for MXbean
+            Descriptor desc = mInfo.getDescriptor();
+            String isMxBean = (String) desc.getFieldValue("mxbean");
+            if (isMxBean.equalsIgnoreCase("true"))
+                return true;
+
+            // Check attribute types
             MBeanAttributeInfo[] attrsInfo = mInfo.getAttributes();
             for (MBeanAttributeInfo attrInfo : attrsInfo) {
                 String type = attrInfo.getType();
@@ -63,6 +73,8 @@
                     return false;
                 }
             }
+
+            // Check operation parameters and return types
             MBeanOperationInfo[] operations = mInfo.getOperations();
             for (MBeanOperationInfo opInfo : operations) {
                 MBeanParameterInfo[] signature = opInfo.getSignature();
@@ -76,7 +88,8 @@
                 }
             }
             return true;
-        } catch (InstanceNotFoundException | IntrospectionException | ReflectionException | ClassNotFoundException ex) {
+        } catch (InstanceNotFoundException | IntrospectionException |
+                ReflectionException | ClassNotFoundException ex) {
             ex.printStackTrace();
             return false;
         }
@@ -113,6 +126,8 @@
         allowedMbeans = new ArrayList<>();
         introspectMBeanTypes(mBeanServer);
         allowedMbeans = new CopyOnWriteArrayList<>(allowedMbeans);
+
+        // Create a REST handler for each MBean
         allowedMbeans.forEach(objectName -> mBeanResourceMap.put(objectName.toString(),
                 new MBeanResource(mBeanServer, objectName)));
     }
@@ -136,7 +151,7 @@
                 }
                 MBeanResource mBeanResource = mBeanResourceMap.get(mBeanName);
                 if (mBeanResource == null) {
-                    HttpUtil.sendResponse(exchange, new HttpResponse(404, "Not found"));
+                    HttpUtil.sendResponse(exchange, HttpResponse.REQUEST_NOT_FOUND);
                     return;
                 }
                 mBeanResource.handle(exchange);
@@ -146,20 +161,21 @@
 
     @Override
     public HttpResponse doGet(HttpExchange exchange) {
-        // add links
-
-        final String path = PlatformRestAdapter.getDomain() + exchange.getRequestURI().getPath().replaceAll("\\/$", "");
+        final String path = PlatformRestAdapter.getDomain()
+                + exchange.getRequestURI().getPath().replaceAll("/$", "");
         try {
-            List<ObjectName> mbeans = allowedMbeans;
+            List<ObjectName> filteredMBeans = allowedMbeans;
             Map<String, String> queryMap = HttpUtil.getGetRequestQueryMap(exchange);
-            if (queryMap.containsKey("query")) {
-                Set<ObjectName> queryMBeans = mBeanServer.queryNames(new ObjectName(queryMap.get("query")), null);
-                queryMBeans.retainAll(allowedMbeans);
-                mbeans = new ArrayList<>(queryMBeans);
+            if (queryMap.containsKey("query")) {        // Filter based on ObjectName query
+                Set<ObjectName> queryMBeans = mBeanServer
+                        .queryNames(new ObjectName(queryMap.get("query")), null);
+                queryMBeans.retainAll(allowedMbeans);   // Intersection of two lists
+                filteredMBeans = new ArrayList<>(queryMBeans);
             }
 
-            JSONObject _links = HttpUtil.getPaginationLinks(exchange, mbeans, pageSize);
-            List<ObjectName> filteredMBeans = HttpUtil.filterByPage(exchange, mbeans, pageSize);
+            JSONObject _links = HttpUtil.getPaginationLinks(exchange, filteredMBeans, pageSize);
+            filteredMBeans = HttpUtil.filterByPage(exchange, filteredMBeans, pageSize);
+
             List<Map<String, String>> items = new ArrayList<>(filteredMBeans.size());
             filteredMBeans.forEach(objectName -> {
                 Map<String, String> item = new LinkedHashMap<>(2);
@@ -172,7 +188,7 @@
 
             Map<String, String> properties = new HashMap<>();
 
-            properties.put("mbeanCount", Integer.toString(mbeans.size()));
+            properties.put("mbeanCount", Integer.toString(filteredMBeans.size()));
 
             JSONMapper typeMapper1 = JSONMappingFactory.INSTANCE.getTypeMapper(items);
             JSONMapper typeMapper2 = JSONMappingFactory.INSTANCE.getTypeMapper(properties);
@@ -180,29 +196,24 @@
             JSONElement linkElem = typeMapper1.toJsonValue(items);
             JSONElement propElem = typeMapper2.toJsonValue(properties);
             JSONObject jobj = new JSONObject();
+
+            jobj.putAll((JSONObject) propElem);
+            jobj.put("mbeans", linkElem);
+
             if (_links != null && !_links.isEmpty()) {
                 jobj.put("_links", _links);
             }
-
-            jobj.putAll((JSONObject) propElem);
-            jobj.put("items", linkElem);
-
-            return new HttpResponse(200, jobj.toJsonString());
+            return new HttpResponse(jobj.toJsonString());
         } catch (JSONMappingException e) {
-            return new HttpResponse(500, "Internal server error");
+            return HttpResponse.SERVER_ERROR;
         } catch (UnsupportedEncodingException e) {
-            return HttpResponse.SERVER_ERROR;
+            return HttpResponse.BAD_REQUEST;
         } catch (MalformedObjectNameException e) {
             return new HttpResponse(HttpResponse.BAD_REQUEST, "Invalid query string");
         }
     }
 
     @Override
-    public HttpResponse doPut(HttpExchange exchange) {
-        return null;
-    }
-
-    @Override
     public HttpResponse doPost(HttpExchange exchange) {
         String path = exchange.getRequestURI().getPath();
         String reqBody = null;
@@ -224,22 +235,20 @@
                 JSONObject result = new JSONObject();
                 for (String mBeanName : jsonObject.keySet()) {
                     MBeanResource mBeanResource = mBeanResourceMap.get(mBeanName);
-                    try {
-                    if (mBeanResource == null) {
-                        result.put(mBeanName, "Invalid MBean");
-                    } else {
+                    if (mBeanResource != null) {
                         JSONElement element = jsonObject.get(mBeanName);
                         if (element instanceof JSONObject) {
-                            JSONElement res = mBeanResource.handleBulkRequest(exchange, (JSONObject) element);
+                            JSONElement res = mBeanResource.handleBulkRequest
+                                    ((JSONObject) element);
                             result.put(mBeanName, res);
                         } else {
                             result.put(mBeanName, "Invalid input");
                         }
-                    }} catch (Throwable e) {
-                        e.printStackTrace();
+                    } else {
+                        result.put(mBeanName, "Invalid MBean");
                     }
                 }
-                return new HttpResponse(HttpURLConnection.HTTP_OK, result.toJsonString());
+                return new HttpResponse(result.toJsonString());
             } else {
                 return HttpResponse.METHOD_NOT_ALLOWED;
             }
@@ -249,14 +258,4 @@
             return HttpResponse.BAD_REQUEST;
         }
     }
-
-    @Override
-    public HttpResponse doDelete(HttpExchange exchange) {
-        return null;
-    }
-
-    @Override
-    public HttpResponse doHead(HttpExchange exchange) {
-        return null;
-    }
 }
--- a/src/java.management.rest/share/classes/com/oracle/jmx/remote/rest/http/MBeanResource.java	Thu Dec 28 14:43:34 2017 +0530
+++ b/src/java.management.rest/share/classes/com/oracle/jmx/remote/rest/http/MBeanResource.java	Thu Dec 28 20:05:03 2017 +0530
@@ -47,6 +47,8 @@
 import java.util.*;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import static javax.management.MBeanOperationInfo.*;
 
@@ -70,17 +72,298 @@
         primitiveToObject.put("short", Short.TYPE);
     }
 
-    public MBeanResource(MBeanServer mBeanServer, ObjectName objectName) {
+    MBeanResource(MBeanServer mBeanServer, ObjectName objectName) {
         this.mBeanServer = mBeanServer;
         this.objectName = objectName;
     }
 
-    private JSONObject getMBeanInfo(MBeanServer mbeanServer, ObjectName mbean) throws InstanceNotFoundException, IntrospectionException, ReflectionException {
+    @Override
+    public void handle(HttpExchange exchange) throws IOException {
+        String path = exchange.getRequestURI().getPath();
+        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, HttpResponse.REQUEST_NOT_FOUND);
+        }
+    }
+
+    @Override
+    public HttpResponse doGet(HttpExchange exchange) {
+        String path = PlatformRestAdapter.getDomain() +
+                exchange.getRequestURI().getPath().replaceAll("/$", "");
+
+        if (path.endsWith("info")) {
+            return doMBeanInfo();
+        }
+
+        String infoPath = path + "/info";
+
+        try {
+            Map<String, Object> allAttributes = getAllAttributes();
+            Map<String, String> _links = new LinkedHashMap<>();
+            _links.put("info", HttpUtil.escapeUrl(infoPath));
+
+            MBeanOperationInfo[] opInfo = mBeanServer.getMBeanInfo(objectName).getOperations();
+            JSONArray jarr = new JSONArray();
+            for (MBeanOperationInfo op : opInfo) {
+                JSONObject jobj1 = new JSONObject();
+                JSONArray jarr1 = new JSONArray();
+                jobj1.put("name", op.getName());
+                jobj1.put("href", HttpUtil.escapeUrl(path + "/" + op.getName()));
+                jobj1.put("method", "POST");
+                for (MBeanParameterInfo paramInfo : op.getSignature()) {
+                    JSONObject jobj = new JSONObject();
+                    jobj.put("name", paramInfo.getName());
+                    jobj.put("type", paramInfo.getType());
+                    jarr1.add(jobj);
+                }
+                jobj1.put("arguments", jarr1);
+                jobj1.put("returnType", op.getReturnType());
+                jarr.add(jobj1);
+            }
+
+            JSONMapper typeMapper = JSONMappingFactory.INSTANCE.getTypeMapper(allAttributes);
+            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);
+                return new HttpResponse(jobj.toJsonString());
+            } else {
+                return HttpResponse.SERVER_ERROR;
+            }
+        } catch (RuntimeOperationsException | IntrospectionException | ReflectionException
+                | JSONMappingException | MBeanException e) {
+            return HttpResponse.SERVER_ERROR;
+        } catch (InstanceNotFoundException e) {
+            return new HttpResponse(HttpResponse.BAD_REQUEST, "Specified MBean does not exist");
+        } catch (Exception e) {
+            return HttpResponse.SERVER_ERROR;
+        }
+    }
+
+    /*
+    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 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.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;
+
+                // Handle bulk operation
+                if (jsonObject.keySet().contains("attributes") | jsonObject.keySet().contains("operations")) {
+                    return new HttpResponse(handleBulkRequest(jsonObject).toJsonString());
+                } else {    // Handle attribute update
+                    Map<String, Object> 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()) {
+                    operation = path.substring(matcher.end());
+                } else {
+                    return HttpResponse.BAD_REQUEST;
+                }
+
+                reqBody = HttpUtil.readRequestBody(exchange);
+                JSONElement result;
+                if (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 (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 doMBeanInfo() {
+        try {
+            JSONObject mBeanInfo = getMBeanInfo(mBeanServer, objectName);
+            return new HttpResponse(mBeanInfo.toJsonString());
+        } catch (RuntimeOperationsException | IntrospectionException | ReflectionException e) {
+            return HttpResponse.SERVER_ERROR;
+        } catch (InstanceNotFoundException e) {
+            return new HttpResponse(HttpResponse.BAD_REQUEST, "Specified MBean does not exist");
+        } catch (Exception e) {
+            return HttpResponse.SERVER_ERROR;
+        }
+    }
+
+    JSONElement handleBulkRequest(JSONObject reqObject) {
+        JSONObject result = new JSONObject();
+
+        // 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) {
+                if (read instanceof JSONArray) {
+                    JSONArray jsonAttrMap = (JSONArray) read;
+                    JSONElement resultJson;
+                    Map<String, Object> attrRead;
+                    try {
+                        String[] attributes = getStrings(jsonAttrMap);
+                        attrRead = getAttributes(attributes);
+                        JSONMapper typeMapper = JSONMappingFactory.INSTANCE.getTypeMapper(attrRead);
+                        resultJson = typeMapper.toJsonValue(attrRead);
+                    } catch (InstanceNotFoundException | ReflectionException | JSONMappingException | MBeanException e) {
+                        resultJson = new JSONPrimitive("<ERROR: Unable to retrieve value>");
+                    } catch (JSONDataException e) {
+                        resultJson = new JSONPrimitive("Invalid JSON : " + e.getMessage());
+                    }
+                    attrNode.put("get", resultJson);
+                } else {
+                    attrInfo.put("get", new JSONPrimitive("Invalid JSON : " + read.toJsonString()));
+                }
+            }
+
+            // Write attributes
+            JSONElement write = attrInfo.get("set");
+
+            if (write != null) {
+                if (write instanceof JSONObject) {
+                    JSONElement resultJson;
+                    JSONObject jsonAttrMap = (JSONObject) write;
+                    try {
+                        Map<String, Object> attrMap = setAttributes(jsonAttrMap);
+                        JSONMapper typeMapper = JSONMappingFactory.INSTANCE.getTypeMapper(attrMap);
+                        resultJson = typeMapper.toJsonValue(attrMap);
+                    } catch (JSONDataException ex) {
+                        resultJson = new JSONPrimitive("Invalid JSON : " + write.toJsonString());
+                    } catch (JSONMappingException | IntrospectionException | InstanceNotFoundException | ReflectionException e) {
+                        resultJson = new JSONPrimitive("<ERROR: Unable to retrieve value>");
+                    }
+                    attrNode.put("set", resultJson);
+                } else {
+                    attrNode.put("set", new JSONPrimitive("Invalid JSON : " + write.toJsonString()));
+                }
+            }
+            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();
+            operationList.forEach((elem) -> {
+                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, "<ERROR while executing operation>");
+                    }
+                } else if (elem instanceof JSONObject) {
+                    ((JSONObject) elem).keySet().forEach((opName) -> {
+                        try {
+                            JSONElement jsonElement = ((JSONObject) elem).get(opName);
+                            if (jsonElement instanceof JSONObject) {
+                                JSONElement obj = execOperation(opName, (JSONObject) jsonElement);
+                                opResult.put(opName, obj);
+                            } else {
+                                opResult.put(opName, new JSONPrimitive("Invalid parameter JSON"));
+                            }
+                        } catch (IllegalArgumentException e) {
+                            opResult.put(opName, e.getMessage());
+                        } catch (IntrospectionException | InstanceNotFoundException
+                                | MBeanException | ReflectionException e) {
+                            opResult.put(opName, "<ERROR while executing operation>");
+                        }
+                    });
+                }
+            });
+            result.put("operations", opResult);
+        }
+        return result;
+    }
+
+    private JSONObject getMBeanInfo(MBeanServer mbeanServer, ObjectName mbean)
+            throws InstanceNotFoundException, IntrospectionException, ReflectionException {
+
         JSONObject jobj = new JSONObject();
         MBeanInfo mBeanInfo = mbeanServer.getMBeanInfo(mbean);
         if (mBeanInfo == null) {
             return jobj;
         }
+        jobj.put("name", mbean.toString());
+        jobj.put("className", mBeanInfo.getClassName());
         jobj.put("description", mBeanInfo.getDescription());
 
         // Populate Attribute Info
@@ -109,6 +392,7 @@
         }
         jobj.put("attributeInfo", jarr);
 
+
         // Add constructor Info
         MBeanConstructorInfo[] constructorInfo = mBeanInfo.getConstructors();
         jarr = new JSONArray();
@@ -172,9 +456,7 @@
         jarr = new JSONArray();
 
         for (MBeanNotificationInfo notification : notifications) {
-
             JSONObject jobj1 = new JSONObject();
-
             jobj1.put("name", notification.getName());
             JSONArray jarr1 = new JSONArray();
             for (String notifType : notification.getNotifTypes()) {
@@ -195,11 +477,11 @@
 
     private JSONObject getParamJSON(MBeanParameterInfo mParamInfo) {
         JSONObject jobj1 = new JSONObject();
+        jobj1.put("name", mParamInfo.getName());
+        jobj1.put("type", mParamInfo.getType());
         if (mParamInfo.getDescription() != null && !mParamInfo.getDescription().isEmpty()) {
             jobj1.put("description", mParamInfo.getDescription());
         }
-        jobj1.put("name", mParamInfo.getName());
-        jobj1.put("type", mParamInfo.getType());
         if (mParamInfo.getDescriptor() != null && mParamInfo.getDescriptor().getFieldNames().length > 1) {
             jobj1.put("descriptor", getDescriptorJSON(mParamInfo.getDescriptor()));
         }
@@ -208,85 +490,71 @@
 
     private JSONObject getDescriptorJSON(Descriptor descriptor) {
         JSONObject jobj2 = new JSONObject();
-        try {
-            String[] descNames = descriptor.getFieldNames();
-            for (String descName : descNames) {
-                Object fieldValue = descriptor.getFieldValue(descName);
-                jobj2.put(descName, fieldValue != null ? fieldValue.toString() : null);
-            }
-        } catch (Throwable t) {
-            t.printStackTrace();
+        String[] descNames = descriptor.getFieldNames();
+        for (String descName : descNames) {
+            Object fieldValue = descriptor.getFieldValue(descName);
+            jobj2.put(descName, fieldValue != null ? fieldValue.toString() : null);
         }
         return jobj2;
     }
 
-    private Map<String, Object> getAttributes(String[] attrs) throws InstanceNotFoundException,
-            ReflectionException {
+    private Map<String, Object> getAttributes(String[] attrs) throws
+            InstanceNotFoundException, ReflectionException, MBeanException {
+
         Map<String, Object> result = new LinkedHashMap<>();
+
         if (attrs == null || attrs.length == 0) {
             return result;
         }
+
         AttributeList attrVals = mBeanServer.getAttributes(objectName, attrs);
-        if (attrVals.size() != attrs.length) {
-            List<String> 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;
-    }
+        List<String> missingAttrs = Arrays.asList(attrs);
+        attrVals.asList().forEach(a -> {
+            missingAttrs.remove(a.getName());
+            result.put(a.getName(), a.getValue());
+        });
 
-    private Map<String, Object> getAllAttributes() throws IntrospectionException,
-            InstanceNotFoundException, ReflectionException, AttributeNotFoundException, MBeanException {
-        Map<String, Object> result = new HashMap<>();
-        MBeanInfo mInfo = mBeanServer.getMBeanInfo(objectName);
-        String[] attrs = Arrays.stream(mInfo.getAttributes())
-                .map(MBeanAttributeInfo::getName)
-                .toArray(String[]::new);
-        AttributeList attrVals = mBeanServer.getAttributes(objectName, attrs);
-        if (attrVals.size() != attrs.length) {
-            List<String> 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) {
+            try {
+                mBeanServer.getAttribute(objectName, attr);
+                result.put(attr, "< Error: No such attribute >");
+            } catch (RuntimeException ex) {
+                if (ex.getCause() instanceof UnsupportedOperationException) {
+                    result.put(attr, "< Attribute not supported >");
+                } else if (ex.getCause() instanceof IllegalArgumentException) {
+                    result.put(attr, "< Invalid attributes >");
+                }
+            } catch (AttributeNotFoundException e) {
+                result.put(attr, "< Attribute not found >");
             }
-            for (String attr : missingAttrs) {
-                try {
-                    Object attribute = mBeanServer.getAttribute(objectName, attr);
-                } catch (RuntimeException ex) {
-                    if (ex.getCause() instanceof UnsupportedOperationException) {
-                        result.put(attr, "< Attribute not supported >");
-                    } else if (ex.getCause() instanceof IllegalArgumentException) {
-                        result.put(attr, "< Invalid attributes >");
-                    }
-                    continue;
-                }
-                result.put(attr, "< Error: No such attribute >");
-            }
-        } else {
-            attrVals.asList().forEach((a) -> {
-                result.put(a.getName(), a.getValue());
-            });
         }
         return result;
     }
 
+    private Map<String, Object> getAllAttributes() throws InstanceNotFoundException,
+            ReflectionException, MBeanException, IntrospectionException {
+
+        MBeanInfo mInfo = mBeanServer.getMBeanInfo(objectName);
+        String[] attrs = Stream.of(mInfo.getAttributes())
+                .map(MBeanAttributeInfo::getName)
+                .toArray(String[]::new);
+
+        return getAttributes(attrs);
+    }
+
     private Map<String, Object> setAttributes(JSONObject attrMap) throws JSONDataException,
             IntrospectionException, InstanceNotFoundException, ReflectionException {
+
         if (attrMap == null || attrMap.isEmpty()) {
             throw new JSONDataException("Null arguments for set attribute");
         }
+
+        MBeanInfo mBeanInfo = mBeanServer.getMBeanInfo(objectName);
         Map<String, Object> 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);
+            MBeanAttributeInfo attrInfo = Arrays.stream(mBeanInfo.getAttributes()).
+                    filter(a -> a.getName().equals(attrName)).findFirst().orElse(null);
             if (attrInfo == null) {
                 result.put(attrName, "<Attribute not found>");
             } else if (!attrInfo.isWritable()) {
@@ -303,7 +571,8 @@
                             inputCls = Class.forName(attrInfo.getType());
                         }
                     } catch (ClassNotFoundException | ClassCastException ex) {
-                        throw new IllegalArgumentException("Invalid parameters : " + attrMap.get(attrName).toJsonString() + " cannot be mapped to : " + attrInfo.getType());
+                        throw new IllegalArgumentException("Invalid parameters : "
+                                + attrMap.get(attrName).toJsonString() + " cannot be mapped to : " + attrInfo.getType());
                     }
                     mapper = JSONMappingFactory.INSTANCE.getTypeMapper(inputCls);
                 }
@@ -324,7 +593,7 @@
         return result;
     }
 
-    private Object mapJsonToType(JSONElement jsonElement, MBeanParameterInfo type) {
+    private Object mapJsonElemToType(JSONElement jsonElement, MBeanParameterInfo type) {
         if (type instanceof OpenMBeanParameterInfo) {
             OpenType<?> openType = ((OpenMBeanParameterInfo) type).getOpenType();
             JSONMapper typeMapper = JSONMappingFactory.INSTANCE.getTypeMapper(openType);
@@ -354,23 +623,23 @@
         }
     }
 
-    private Map<String, Object> getParameters(Map<String, JSONElement> jsonValues, Map<String, MBeanParameterInfo> typeMap) {
+    private Map<String, Object> getOperationParameters(Map<String, JSONElement> jsonValues, Map<String, MBeanParameterInfo> 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<String, Object> parameters = new LinkedHashMap<>();
-        if (typeMap.size() == 0 && jsonValues.isEmpty()) {
+        Map<String, Object> parameters = new LinkedHashMap<>(); // Order of parameters should be same as typeMap
+        if (typeMap.isEmpty() && jsonValues.isEmpty()) {
             return parameters;
         }
-        for (String name : typeMap.keySet()) {
+        typeMap.keySet().forEach((name) -> {
             MBeanParameterInfo type = typeMap.get(name);
             JSONElement jsonVal = jsonValues.get(name);
-            Object obj = mapJsonToType(jsonVal, type);
+            Object obj = mapJsonElemToType(jsonVal, type);
             parameters.put(name, obj);
-        }
+        });
         return parameters;
     }
 
@@ -386,43 +655,35 @@
             throw new IllegalArgumentException("MBean does not exist");
         }
 
-        MBeanOperationInfo[] opinfos = Arrays.stream(mBeanInfo.getOperations()).
-                filter(a -> a.getName().equals(opstr)).toArray(MBeanOperationInfo[]::new);
+        List<MBeanOperationInfo> mBeanOperationInfos = Arrays.stream(mBeanInfo.getOperations()).
+                filter(a -> a.getName().equals(opstr)).collect(Collectors.toList());
 
-        if (opinfos.length == 0) {
+        if (mBeanOperationInfos.isEmpty()) {
             throw new IllegalArgumentException("Invalid Operation String");
         }
 
         String[] signature = null;
         Object[] parameters = null;
 
-        if (opinfos.length == 1) {
-            MBeanParameterInfo[] sig = opinfos[0].getSignature();
-            Map<String, MBeanParameterInfo> 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<String, MBeanParameterInfo> 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;
+        IllegalArgumentException exception = null;
+        for (MBeanOperationInfo mBeanOperationInfo : mBeanOperationInfos) {
+            MBeanParameterInfo[] sig = mBeanOperationInfo.getSignature();
+            try {
+                Map<String, MBeanParameterInfo> typeMap = new LinkedHashMap<>();    // Order of parameters is important
+                Arrays.stream(sig).forEach(e -> typeMap.put(e.getName(), e));
+                parameters = getOperationParameters(params, typeMap).values().toArray();
+                signature = Stream.of(sig).map(MBeanParameterInfo::getType).toArray(String[]::new);
+                exception = null;
+                break;
+            } catch (IllegalArgumentException ex) {
+                exception = ex;
             }
         }
+        if (exception != null) {
+            throw exception;
+        }
 
-        Object invoke = null;
+        Object invoke;
         try {
             invoke = mBeanServer.invoke(objectName, opstr, parameters, signature);
             if (invoke != null) {
@@ -440,268 +701,6 @@
         }
     }
 
-    private HttpResponse doMBeanInfo(HttpExchange exchange) {
-        try {
-            JSONObject mBeanInfo = getMBeanInfo(mBeanServer, objectName);
-            return new HttpResponse(200, mBeanInfo.toJsonString());
-        } catch (RuntimeOperationsException | IntrospectionException | ReflectionException e) {
-            return new HttpResponse(HttpResponse.SERVER_ERROR, HttpResponse.getErrorMessage(e));
-        } catch (InstanceNotFoundException e) {
-            return new HttpResponse(HttpResponse.BAD_REQUEST, "Specified MBean does not exist");
-        } catch (Exception e) {
-            return new HttpResponse(HttpResponse.SERVER_ERROR, HttpResponse.getErrorMessage(e));
-        }
-    }
-
-    @Override
-    public void handle(HttpExchange exchange) throws IOException {
-        String path = exchange.getRequestURI().getPath();
-        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"));
-        }
-    }
-
-    @Override
-    public HttpResponse doGet(HttpExchange exchange) {
-        if (exchange.getRequestURI().getPath().endsWith("info")) {
-            return doMBeanInfo(exchange);
-        }
-        String path = PlatformRestAdapter.getDomain() + exchange.getRequestURI().getPath().replaceAll("\\/$", "");
-        String info = path + "/info";
-
-        try {
-            Map<String, Object> allAttributes = getAllAttributes();
-            Map<String, String> _links = new LinkedHashMap<>();
-            _links.put("info", HttpUtil.escapeUrl(info));
-
-            MBeanOperationInfo[] opInfo = mBeanServer.getMBeanInfo(objectName).getOperations();
-            JSONArray jarr = new JSONArray();
-            for (MBeanOperationInfo op : opInfo) {
-                JSONObject jobj1 = new JSONObject();
-                JSONArray jarr1 = new JSONArray();
-                jobj1.put("name", op.getName());
-                jobj1.put("href", HttpUtil.escapeUrl(path + "/" + op.getName()));
-                jobj1.put("method", "POST");
-                for (MBeanParameterInfo paramInfo : op.getSignature()) {
-                    JSONObject jobj = new JSONObject();
-                    jobj.put("name", paramInfo.getName());
-                    jobj.put("type", paramInfo.getType());
-                    jarr1.add(jobj);
-                }
-                jobj1.put("arguments", jarr1);
-                jobj1.put("returnType", op.getReturnType());
-                jarr.add(jobj1);
-            }
-
-            JSONMapper typeMapper = JSONMappingFactory.INSTANCE.getTypeMapper(allAttributes);
-            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);
-                return new HttpResponse(200, jobj.toJsonString());
-            } else {
-                return new HttpResponse(HttpResponse.SERVER_ERROR, "Unable to find JSONMapper");
-            }
-        } catch (RuntimeOperationsException | IntrospectionException | ReflectionException | JSONMappingException e) {
-            return new HttpResponse(HttpResponse.SERVER_ERROR, HttpResponse.getErrorMessage(e));
-        } catch (InstanceNotFoundException e) {
-            return new HttpResponse(HttpResponse.BAD_REQUEST, "Specified MBean does not exist");
-        } catch (AttributeNotFoundException e) {
-            return new HttpResponse(HttpResponse.BAD_REQUEST, "Specified Attribute does not exist");
-        } catch (MBeanException e) {
-            Throwable cause = e.getCause();
-            return new HttpResponse(HttpResponse.SERVER_ERROR, HttpResponse.getErrorMessage(e));
-        } catch (Exception e) {
-            return new HttpResponse(HttpResponse.SERVER_ERROR, HttpResponse.getErrorMessage(e));
-        }
-    }
-
-    /*
-    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 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 new HttpResponse(HttpURLConnection.HTTP_OK, handleBulkRequest(exchange, jsonObject).toJsonString());
-                } else {
-                    Map<String, Object> 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 (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;
-    }
-
-    public JSONElement handleBulkRequest(HttpExchange exchange, JSONObject reqObject) {
-
-        JSONObject result = new JSONObject();
-
-        // 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<String, Object> 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("<ERROR: Unable to retrieve value>");
-                } catch (JSONDataException e) {
-                    jAttrRead = new JSONPrimitive("Invalid JSON : " + read.toJsonString());
-                }
-
-                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<String, Object> 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("<ERROR: Unable to retrieve value>");
-                }
-                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, "<ERROR while executing operation>");
-                    }
-                } else if (elem instanceof JSONObject) {
-                    Set<String> opNames = ((JSONObject) element).keySet();
-                    for (String opName : opNames) {
-                        try {
-                            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, "<ERROR while executing operation>");
-                        }
-                    }
-                }
-            }
-            result.put("operations", opResult);
-        }
-        return result;
-    }
-
     private String[] getStrings(JSONArray jsonArray) throws JSONDataException {
         List<String> attributes = new ArrayList<>();
         for (JSONElement element : jsonArray) {
@@ -712,20 +711,4 @@
         }
         return attributes.toArray(new String[0]);
     }
-
-    @Override
-    public HttpResponse doPut(HttpExchange exchange) {
-        return null;
-    }
-
-    @Override
-    public HttpResponse doDelete(HttpExchange exchange) {
-        return null;
-    }
-
-    @Override
-    public HttpResponse doHead(HttpExchange exchange) {
-        return null;
-    }
-
 }