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