From 9eb5eb3f661d68d8087f650d04d1079276d7160f Mon Sep 17 00:00:00 2001 From: Krassimir Valev Date: Wed, 16 May 2018 22:22:03 +0200 Subject: [PATCH 1/5] PAYARA-2744 Monitoring REST API bulk reading #2617 (#2697) * Monitoring REST AI bulk reading * Copyright header --- .../rest/app/MBeanServerDelegate.java | 26 +++- .../rest/app/RestMonitoringAppConfig.java | 6 +- .../handler/MBeanAttributesReadHandler.java | 127 ++++++++++++++++ .../app/resource/MBeanBulkReadResource.java | 141 ++++++++++++++++++ 4 files changed, 297 insertions(+), 3 deletions(-) create mode 100644 appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/handler/MBeanAttributesReadHandler.java create mode 100644 appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/resource/MBeanBulkReadResource.java diff --git a/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/MBeanServerDelegate.java b/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/MBeanServerDelegate.java index 5cb90172848..7842957ed93 100644 --- a/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/MBeanServerDelegate.java +++ b/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/MBeanServerDelegate.java @@ -40,8 +40,10 @@ package fish.payara.monitoring.rest.app; import static java.lang.management.ManagementFactory.getPlatformMBeanServer; + import javax.ejb.Startup; import javax.inject.Singleton; +import javax.management.AttributeList; import javax.management.AttributeNotFoundException; import javax.management.InstanceNotFoundException; import javax.management.IntrospectionException; @@ -53,7 +55,7 @@ import javax.management.ReflectionException; /** - * + * * @author Fraser Savage */ @Startup @@ -102,6 +104,28 @@ public Object getMBeanAttribute(String mbeanname, String attributename) throws M return platformServer.getAttribute(getMBeanName(mbeanname), attributename); } + /** + * Retrieves the values of several attributes of a named MBean. The MBean is identified by its object name. + * If one or more attributes cannot be retrieved for some reason, they will be omitted from the returned + * {@code AttributeList}. + * + * @param mbeanname + * The object name of the MBean from which the attributes are retrieved. + * @param attributenames + * A list of the attributes to be retrieved. + * @return The list of the retrieved attributes. + * @throws InstanceNotFoundException + * {@inheritDoc} + * @throws MalformedObjectNameException + * {@inheritDoc} + * @throws ReflectionException + * {@inheritDoc} + */ + public AttributeList getMBeanAttributes(final String mbeanname, final String[] attributenames) + throws InstanceNotFoundException, MalformedObjectNameException, ReflectionException { + return platformServer.getAttributes(getMBeanName(mbeanname), attributenames); + } + /** * Returns an {@link ObjectName}. * The mbeanname argument must be a valid {@link ObjectName}. diff --git a/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/RestMonitoringAppConfig.java b/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/RestMonitoringAppConfig.java index 27893b03c89..26a4215a36c 100644 --- a/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/RestMonitoringAppConfig.java +++ b/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/RestMonitoringAppConfig.java @@ -41,6 +41,7 @@ import java.util.HashSet; import java.util.Set; + import javax.ws.rs.ApplicationPath; import javax.ws.rs.core.Application; @@ -51,7 +52,7 @@ // @HOLD - FANG-3: Implement Fang 'State' handler and resource. @ApplicationPath("/rest") public class RestMonitoringAppConfig extends Application { - + @Override public Set> getClasses() { Set> resources = new HashSet<>(); @@ -59,8 +60,9 @@ public Set> getClasses() { return resources; } - private void addRestResourceClasses(Set> resources) { + private void addRestResourceClasses(final Set> resources) { resources.add(fish.payara.monitoring.rest.app.resource.MBeanReadResource.class); + resources.add(fish.payara.monitoring.rest.app.resource.MBeanBulkReadResource.class); resources.add(fish.payara.monitoring.rest.app.resource.RestMonitoringAppStateResource.class); } } diff --git a/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/handler/MBeanAttributesReadHandler.java b/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/handler/MBeanAttributesReadHandler.java new file mode 100644 index 00000000000..1fa83ac93cf --- /dev/null +++ b/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/handler/MBeanAttributesReadHandler.java @@ -0,0 +1,127 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2018] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package fish.payara.monitoring.rest.app.handler; + +import java.util.Arrays; + +import javax.inject.Singleton; +import javax.json.Json; +import javax.json.JsonArrayBuilder; +import javax.json.JsonException; +import javax.json.JsonObject; +import javax.json.JsonObjectBuilder; +import javax.json.JsonValue; +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.InstanceNotFoundException; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.ReflectionException; +import javax.ws.rs.core.Response; + +import fish.payara.monitoring.rest.app.MBeanServerDelegate; +import fish.payara.monitoring.rest.app.RestMonitoringAppResponseToken; +import fish.payara.monitoring.rest.app.processor.ProcessorFactory; +import fish.payara.monitoring.rest.app.processor.TypeProcessor; + +/** + * @author Krassimir Valev + */ +public class MBeanAttributesReadHandler extends ReadHandler { + + private final String mbeanname; + private final String[] attributenames; + + /** + * Creates an instance of MBeanAttributeReadHandler, which handles bulk MBean + * attribute read requests. + * + * @param delegate + * The {@link MBeanServerDelegate} to get information from. + * @param mbeanname + * The {@link ObjectName} of the MBean to get information from. + * @param attributename + * The name of the MBean attribute to get values for. + */ + public MBeanAttributesReadHandler(@Singleton final MBeanServerDelegate delegate, + final String mbeanname, final String[] attributenames) { + super(delegate); + this.mbeanname = mbeanname; + this.attributenames = attributenames; + } + + @Override + public JsonObject getRequestObject() { + JsonObjectBuilder objectBuilder = Json.createObjectBuilder(); + try { + objectBuilder.add(RestMonitoringAppResponseToken.getMbeanNameKey(), mbeanname); + objectBuilder.add(RestMonitoringAppResponseToken.getAttributeNameKey(), + Json.createArrayBuilder(Arrays.asList(attributenames))); + objectBuilder.add(RestMonitoringAppResponseToken.getRequestTypeKey(), requesttype); + } catch (JsonException ex) { + super.setStatus(Response.Status.INTERNAL_SERVER_ERROR); + } + return objectBuilder.build(); + } + + @Override + public JsonValue getValueObject() throws JsonException { + try { + AttributeList attributes = delegate.getMBeanAttributes(mbeanname, attributenames); + + // the javax.management.Attribute type does not inherit from OpenType, so the existing + // ProcessorFactory and TypeProcessor infrastructure cannot be used + JsonArrayBuilder arrayBuilder = Json.createArrayBuilder(); + + for (Attribute attribute : attributes.asList()) { + TypeProcessor processor = ProcessorFactory.getTypeProcessor(attribute.getValue()); + + JsonObjectBuilder objectBuilder = Json.createObjectBuilder(); + objectBuilder.add(attribute.getName(), processor.processObject(attribute.getValue())); + arrayBuilder.add(objectBuilder); + } + + return arrayBuilder.build(); + } catch (InstanceNotFoundException | ReflectionException | MalformedObjectNameException ex) { + super.setStatus(Response.Status.NOT_FOUND); + return getTraceObject(ex); + } + } +} diff --git a/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/resource/MBeanBulkReadResource.java b/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/resource/MBeanBulkReadResource.java new file mode 100644 index 00000000000..b103309301c --- /dev/null +++ b/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/resource/MBeanBulkReadResource.java @@ -0,0 +1,141 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2018] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package fish.payara.monitoring.rest.app.resource; + +import java.io.StringReader; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +import javax.json.Json; +import javax.json.JsonArrayBuilder; +import javax.json.JsonObject; +import javax.json.JsonReader; +import javax.json.JsonString; +import javax.json.JsonStructure; +import javax.json.JsonValue; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import fish.payara.monitoring.rest.app.MBeanServerDelegate; +import fish.payara.monitoring.rest.app.handler.MBeanAttributeReadHandler; +import fish.payara.monitoring.rest.app.handler.MBeanAttributesReadHandler; +import fish.payara.monitoring.rest.app.handler.MBeanReadHandler; +import fish.payara.monitoring.rest.app.handler.ReadHandler; + +/** + * @author Krassimir Valev + */ +@Path("") +@RequestScoped +public class MBeanBulkReadResource { + + @Inject + private MBeanServerDelegate mDelegate; + + /** + * Returns the {@link String} form of the {@link JSONObject} resource from the ResourceHandler. + * + * @param content + * The JSON request payload, describing the beans and attributes to read. + * @return The {@link String} representation of the MBeanRead/MBeanAttributeRead {@link JSONObject}. + */ + @POST + @Produces(MediaType.APPLICATION_JSON) + public String getReadResource(final String content) { + try (JsonReader reader = Json.createReader(new StringReader(content))) { + // the payload can be either a single request or a bulk one (array) + JsonStructure struct = reader.read(); + switch (struct.getValueType()) { + case ARRAY: + List objects = struct.asJsonArray().stream() + .map(value -> handleRequest(value.asJsonObject())) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toList()); + + JsonArrayBuilder builder = Json.createArrayBuilder(); + for (JsonObject jsonObject : objects) { + builder.add(jsonObject); + } + + return builder.build().toString(); + case OBJECT: + return handleRequest(struct.asJsonObject()).orElse(JsonValue.EMPTY_JSON_OBJECT).toString(); + default: + return "invalid JSON structure"; + } + } + } + + private Optional handleRequest(final JsonObject jsonObject) { + // ignore non-read requests + String type = jsonObject.getString("type", ""); + if (!"read".equalsIgnoreCase(type)) { + return Optional.empty(); + } + + String mbean = jsonObject.getString("mbean", ""); + JsonValue attributes = jsonObject.getOrDefault("attribute", JsonValue.NULL); + ReadHandler handler = getReadHandler(mbean, attributes); + return Optional.of(handler.getResource()); + } + + private ReadHandler getReadHandler(final String mbean, final JsonValue attributes) { + // attributes can be null, a string or a list of strings + switch (attributes.getValueType()) { + case ARRAY: + String[] attributeNames = attributes.asJsonArray().stream() + .map(v -> ((JsonString) v).getString()) + .toArray(String[]::new); + return new MBeanAttributesReadHandler(mDelegate, mbean, attributeNames); + case STRING: + String attribute = ((JsonString) attributes).getString(); + return new MBeanAttributeReadHandler(mDelegate, mbean, attribute); + default: + return new MBeanReadHandler(mDelegate, mbean); + } + } + +} From 1ebe969f6114a46a1d63abb7d5b8ce58163f2494 Mon Sep 17 00:00:00 2001 From: merorai Date: Tue, 29 May 2018 09:57:15 +0100 Subject: [PATCH 2/5] Initial commit --- .../app/resource/MBeanBulkReadResource.java | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/resource/MBeanBulkReadResource.java b/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/resource/MBeanBulkReadResource.java index b103309301c..35586edfefa 100644 --- a/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/resource/MBeanBulkReadResource.java +++ b/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/resource/MBeanBulkReadResource.java @@ -63,6 +63,7 @@ import fish.payara.monitoring.rest.app.handler.MBeanAttributesReadHandler; import fish.payara.monitoring.rest.app.handler.MBeanReadHandler; import fish.payara.monitoring.rest.app.handler.ReadHandler; +import java.util.ArrayList; /** * @author Krassimir Valev @@ -89,12 +90,22 @@ public String getReadResource(final String content) { JsonStructure struct = reader.read(); switch (struct.getValueType()) { case ARRAY: - List objects = struct.asJsonArray().stream() - .map(value -> handleRequest(value.asJsonObject())) - .filter(Optional::isPresent) - .map(Optional::get) - .collect(Collectors.toList()); - +// List objects = struct.asJsonArray().stream() +// .map(value -> handleRequest(value.asJsonObject())) +// .filter(Optional::isPresent) +// .map(Optional::get) +// .collect(Collectors.toList()); + + //List objects1 = struct.asJsonArray(). + List objects = new ArrayList<>(); + + for (JsonValue jsonValue : struct.asJsonArray()){ + JsonObject response = handleRequest(jsonValue.asJsonObject()); + if (response != null){ + objects.add(response); + } + } + JsonArrayBuilder builder = Json.createArrayBuilder(); for (JsonObject jsonObject : objects) { builder.add(jsonObject); @@ -102,24 +113,26 @@ public String getReadResource(final String content) { return builder.build().toString(); case OBJECT: - return handleRequest(struct.asJsonObject()).orElse(JsonValue.EMPTY_JSON_OBJECT).toString(); + //return handleRequest(struct.asJsonObject()).orElse(JsonValue.EMPTY_JSON_OBJECT).toString(); + return handleRequest(struct.asJsonObject()).toString() != null ? handleRequest(struct.asJsonObject()).toString() : JsonValue.EMPTY_JSON_OBJECT.toString(); + default: return "invalid JSON structure"; } } } - private Optional handleRequest(final JsonObject jsonObject) { + private JsonObject handleRequest(final JsonObject jsonObject) { // ignore non-read requests String type = jsonObject.getString("type", ""); if (!"read".equalsIgnoreCase(type)) { - return Optional.empty(); + return null; } String mbean = jsonObject.getString("mbean", ""); JsonValue attributes = jsonObject.getOrDefault("attribute", JsonValue.NULL); ReadHandler handler = getReadHandler(mbean, attributes); - return Optional.of(handler.getResource()); + return handler.getResource(); } private ReadHandler getReadHandler(final String mbean, final JsonValue attributes) { From 7879be59a248a8943b212865ea8d8e9c9c3ce979 Mon Sep 17 00:00:00 2001 From: merorai Date: Thu, 31 May 2018 11:54:30 +0100 Subject: [PATCH 3/5] Downported Bulk Read for REST monitoring --- .../handler/MBeanAttributesReadHandler.java | 48 +++--- .../app/resource/MBeanBulkReadResource.java | 143 ++++++++++-------- 2 files changed, 106 insertions(+), 85 deletions(-) diff --git a/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/handler/MBeanAttributesReadHandler.java b/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/handler/MBeanAttributesReadHandler.java index 1fa83ac93cf..504a4e50f4c 100644 --- a/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/handler/MBeanAttributesReadHandler.java +++ b/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/handler/MBeanAttributesReadHandler.java @@ -39,27 +39,25 @@ */ package fish.payara.monitoring.rest.app.handler; -import java.util.Arrays; - import javax.inject.Singleton; -import javax.json.Json; -import javax.json.JsonArrayBuilder; -import javax.json.JsonException; -import javax.json.JsonObject; -import javax.json.JsonObjectBuilder; -import javax.json.JsonValue; import javax.management.Attribute; import javax.management.AttributeList; import javax.management.InstanceNotFoundException; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import javax.management.ReflectionException; -import javax.ws.rs.core.Response; import fish.payara.monitoring.rest.app.MBeanServerDelegate; import fish.payara.monitoring.rest.app.RestMonitoringAppResponseToken; import fish.payara.monitoring.rest.app.processor.ProcessorFactory; import fish.payara.monitoring.rest.app.processor.TypeProcessor; +import java.util.Arrays; +import org.codehaus.jettison.json.JSONArray; +import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.JSONObject; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.ws.rs.core.Response; /** * @author Krassimir Valev @@ -88,37 +86,39 @@ public MBeanAttributesReadHandler(@Singleton final MBeanServerDelegate delegate, } @Override - public JsonObject getRequestObject() { - JsonObjectBuilder objectBuilder = Json.createObjectBuilder(); + public JSONObject getRequestObject() { + JSONObject requestObject = new JSONObject(); try { - objectBuilder.add(RestMonitoringAppResponseToken.getMbeanNameKey(), mbeanname); - objectBuilder.add(RestMonitoringAppResponseToken.getAttributeNameKey(), - Json.createArrayBuilder(Arrays.asList(attributenames))); - objectBuilder.add(RestMonitoringAppResponseToken.getRequestTypeKey(), requesttype); - } catch (JsonException ex) { - super.setStatus(Response.Status.INTERNAL_SERVER_ERROR); + requestObject.put(RestMonitoringAppResponseToken.getMbeanNameKey(), mbeanname); + requestObject.put(RestMonitoringAppResponseToken.getMbeanNameKey(), mbeanname); + requestObject.put(RestMonitoringAppResponseToken.getAttributeNameKey(), + new JSONArray(Arrays.asList(attributenames))); + requestObject.put(RestMonitoringAppResponseToken.getRequestTypeKey(), requesttype); + + } catch (JSONException ex) { + Logger.getLogger(MBeanAttributesReadHandler.class.getName()).log(Level.SEVERE, null, ex); } - return objectBuilder.build(); + return requestObject; } @Override - public JsonValue getValueObject() throws JsonException { + public Object getValueObject() throws JSONException { try { AttributeList attributes = delegate.getMBeanAttributes(mbeanname, attributenames); // the javax.management.Attribute type does not inherit from OpenType, so the existing // ProcessorFactory and TypeProcessor infrastructure cannot be used - JsonArrayBuilder arrayBuilder = Json.createArrayBuilder(); + JSONArray jsonArray = new JSONArray(); for (Attribute attribute : attributes.asList()) { TypeProcessor processor = ProcessorFactory.getTypeProcessor(attribute.getValue()); - JsonObjectBuilder objectBuilder = Json.createObjectBuilder(); - objectBuilder.add(attribute.getName(), processor.processObject(attribute.getValue())); - arrayBuilder.add(objectBuilder); + JSONObject valueObject = new JSONObject(); + valueObject.put(attribute.getName(), processor.processObject(attribute.getValue())); + jsonArray.put(valueObject); } - return arrayBuilder.build(); + return jsonArray; } catch (InstanceNotFoundException | ReflectionException | MalformedObjectNameException ex) { super.setStatus(Response.Status.NOT_FOUND); return getTraceObject(ex); diff --git a/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/resource/MBeanBulkReadResource.java b/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/resource/MBeanBulkReadResource.java index 35586edfefa..3344c424c0d 100644 --- a/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/resource/MBeanBulkReadResource.java +++ b/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/resource/MBeanBulkReadResource.java @@ -39,20 +39,9 @@ */ package fish.payara.monitoring.rest.app.resource; -import java.io.StringReader; import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; - import javax.enterprise.context.RequestScoped; import javax.inject.Inject; -import javax.json.Json; -import javax.json.JsonArrayBuilder; -import javax.json.JsonObject; -import javax.json.JsonReader; -import javax.json.JsonString; -import javax.json.JsonStructure; -import javax.json.JsonValue; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; @@ -63,7 +52,12 @@ import fish.payara.monitoring.rest.app.handler.MBeanAttributesReadHandler; import fish.payara.monitoring.rest.app.handler.MBeanReadHandler; import fish.payara.monitoring.rest.app.handler.ReadHandler; +import fish.payara.monitoring.rest.app.handler.ResourceHandler; import java.util.ArrayList; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.*; /** * @author Krassimir Valev @@ -76,79 +70,106 @@ public class MBeanBulkReadResource { private MBeanServerDelegate mDelegate; /** - * Returns the {@link String} form of the {@link JSONObject} resource from the ResourceHandler. + * Returns the {@link String} form of the {@link JSONObject} resource from + * the ResourceHandler. * - * @param content - * The JSON request payload, describing the beans and attributes to read. - * @return The {@link String} representation of the MBeanRead/MBeanAttributeRead {@link JSONObject}. + * @param content The JSON request payload, describing the beans and + * attributes to read. + * @return The {@link String} representation of the + * MBeanRead/MBeanAttributeRead {@link JSONObject}. */ @POST @Produces(MediaType.APPLICATION_JSON) - public String getReadResource(final String content) { - try (JsonReader reader = Json.createReader(new StringReader(content))) { - // the payload can be either a single request or a bulk one (array) - JsonStructure struct = reader.read(); - switch (struct.getValueType()) { - case ARRAY: -// List objects = struct.asJsonArray().stream() -// .map(value -> handleRequest(value.asJsonObject())) -// .filter(Optional::isPresent) -// .map(Optional::get) -// .collect(Collectors.toList()); - - //List objects1 = struct.asJsonArray(). - List objects = new ArrayList<>(); - - for (JsonValue jsonValue : struct.asJsonArray()){ - JsonObject response = handleRequest(jsonValue.asJsonObject()); - if (response != null){ - objects.add(response); - } + public String getReadResource(final String content) throws JSONException { + + if (content != null && !content.trim().isEmpty() && isJsonValid(content)) { + Object jsonTokener = new JSONTokener(content).nextValue(); + + if (jsonTokener instanceof JSONObject) { + JSONObject jsonObject = new JSONObject(content); + + try { + JSONObject request = handleRequest(jsonObject); + if (request != null) { + return request.toString(); + } else { + return "{}"; } - - JsonArrayBuilder builder = Json.createArrayBuilder(); - for (JsonObject jsonObject : objects) { - builder.add(jsonObject); + } catch (NullPointerException ex) { + Logger.getLogger(ResourceHandler.class.getName()).log(Level.SEVERE, null, ex); + } + } else if (jsonTokener instanceof JSONArray) { + List objects = new ArrayList<>(); + JSONArray jsonArray = new JSONArray(content); + + for (int i = 0; i < jsonArray.length(); i++) { + System.out.println(jsonArray.getJSONObject(i)); + JSONObject jsonObject = handleRequest(jsonArray.getJSONObject(i)); + + if (jsonObject != null) { + objects.add(jsonObject); } + } + + JSONArray resource = new JSONArray(); - return builder.build().toString(); - case OBJECT: - //return handleRequest(struct.asJsonObject()).orElse(JsonValue.EMPTY_JSON_OBJECT).toString(); - return handleRequest(struct.asJsonObject()).toString() != null ? handleRequest(struct.asJsonObject()).toString() : JsonValue.EMPTY_JSON_OBJECT.toString(); + for (JSONObject jsonObject : objects) { + resource.put(jsonObject); + } - default: - return "invalid JSON structure"; + return resource.toString(); } } + + return "invalid JSON"; } - private JsonObject handleRequest(final JsonObject jsonObject) { + private JSONObject handleRequest(final JSONObject jsonObject) throws JSONException { // ignore non-read requests - String type = jsonObject.getString("type", ""); + String type = jsonObject.optString("type"); if (!"read".equalsIgnoreCase(type)) { return null; } - String mbean = jsonObject.getString("mbean", ""); - JsonValue attributes = jsonObject.getOrDefault("attribute", JsonValue.NULL); + String mbean = jsonObject.optString("mbean"); + String attributes = jsonObject.optString("attribute"); ReadHandler handler = getReadHandler(mbean, attributes); return handler.getResource(); } - private ReadHandler getReadHandler(final String mbean, final JsonValue attributes) { + private ReadHandler getReadHandler(final String mbean, final String attributes) throws JSONException { // attributes can be null, a string or a list of strings - switch (attributes.getValueType()) { - case ARRAY: - String[] attributeNames = attributes.asJsonArray().stream() - .map(v -> ((JsonString) v).getString()) - .toArray(String[]::new); - return new MBeanAttributesReadHandler(mDelegate, mbean, attributeNames); - case STRING: - String attribute = ((JsonString) attributes).getString(); - return new MBeanAttributeReadHandler(mDelegate, mbean, attribute); - default: - return new MBeanReadHandler(mDelegate, mbean); + if (attributes != null && !attributes.trim().isEmpty()) { + Object jsonTokener = new JSONTokener(attributes).nextValue(); + if (jsonTokener instanceof JSONArray) { + List attributeNames = new ArrayList<>(); + + JSONArray jsonArray = new JSONArray(attributes); + + for (int i = 0; i < jsonArray.length(); i++) { + attributeNames.add(jsonArray.get(i).toString()); + } + return new MBeanAttributesReadHandler(mDelegate, mbean, attributeNames.toArray(new String[0])); + + } else if (jsonTokener instanceof String) { + return new MBeanAttributeReadHandler(mDelegate, mbean, attributes); + } + } + + return new MBeanReadHandler(mDelegate, mbean); + } + + private boolean isJsonValid(String jsonString) { + try { + new JSONObject(jsonString); + } catch (JSONException jsonObjectException) { + try { + new JSONArray(jsonString); + } catch (JSONException jsonArrayException) { + return false; + } } + return true; } } From b67afb34ec965b9e876a776644fce473c165655e Mon Sep 17 00:00:00 2001 From: merorai Date: Thu, 31 May 2018 12:01:29 +0100 Subject: [PATCH 4/5] Added a log error meesage --- .../monitoring/rest/app/resource/MBeanBulkReadResource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/resource/MBeanBulkReadResource.java b/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/resource/MBeanBulkReadResource.java index 3344c424c0d..a830262f0ef 100644 --- a/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/resource/MBeanBulkReadResource.java +++ b/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/resource/MBeanBulkReadResource.java @@ -96,7 +96,7 @@ public String getReadResource(final String content) throws JSONException { return "{}"; } } catch (NullPointerException ex) { - Logger.getLogger(ResourceHandler.class.getName()).log(Level.SEVERE, null, ex); + Logger.getLogger(ResourceHandler.class.getName()).log(Level.CONFIG, "NullPointerException when getting Read resources", ex); } } else if (jsonTokener instanceof JSONArray) { List objects = new ArrayList<>(); From b06ecae9498b49fa3d2675749781ebc7a0d0e844 Mon Sep 17 00:00:00 2001 From: merorai Date: Thu, 31 May 2018 15:51:07 +0100 Subject: [PATCH 5/5] Code clean up --- .../monitoring/rest/app/resource/MBeanBulkReadResource.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/resource/MBeanBulkReadResource.java b/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/resource/MBeanBulkReadResource.java index a830262f0ef..00f3aa8afbf 100644 --- a/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/resource/MBeanBulkReadResource.java +++ b/appserver/payara-appserver-modules/rest-monitoring/rest-monitoring-war/src/main/java/fish/payara/monitoring/rest/app/resource/MBeanBulkReadResource.java @@ -103,9 +103,7 @@ public String getReadResource(final String content) throws JSONException { JSONArray jsonArray = new JSONArray(content); for (int i = 0; i < jsonArray.length(); i++) { - System.out.println(jsonArray.getJSONObject(i)); JSONObject jsonObject = handleRequest(jsonArray.getJSONObject(i)); - if (jsonObject != null) { objects.add(jsonObject); }