You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2020/06/10 10:05:46 UTC

[camel] branch master updated: CAMEL-15172: camel-openapi-java - Use non JMX by default to resolve rest-dsl model, and make JMX loaded from classpath when needed. This allows microcontainers like quarkus to easier optimize for this and thrown away unused classes.

This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/master by this push:
     new bc1c19c  CAMEL-15172: camel-openapi-java - Use non JMX by default to resolve rest-dsl model, and make JMX loaded from classpath when needed. This allows microcontainers like quarkus to easier optimize for this and thrown away unused classes.
bc1c19c is described below

commit bc1c19c98ac6161f52430cc12d23e849cc9cead1
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Wed Jun 10 12:05:26 2020 +0200

    CAMEL-15172: camel-openapi-java - Use non JMX by default to resolve rest-dsl model, and make JMX loaded from classpath when needed. This allows microcontainers like quarkus to easier optimize for this and thrown away unused classes.
---
 .../org/apache/camel/jmx-rest-definition-resolver  |  2 +
 .../openapi/DefaultRestDefinitionsResolver.java    | 47 +++++++++++
 .../camel/openapi/RestDefinitionsResolver.java     | 35 ++++++++
 .../apache/camel/openapi/RestOpenApiProcessor.java |  2 +-
 .../apache/camel/openapi/RestOpenApiSupport.java   | 82 +++++-------------
 .../openapi/jmx/JmxRestDefinitionsResolver.java    | 98 ++++++++++++++++++++++
 6 files changed, 205 insertions(+), 61 deletions(-)

diff --git a/components/camel-openapi-java/src/generated/resources/META-INF/services/org/apache/camel/jmx-rest-definition-resolver b/components/camel-openapi-java/src/generated/resources/META-INF/services/org/apache/camel/jmx-rest-definition-resolver
new file mode 100644
index 0000000..ef74d25
--- /dev/null
+++ b/components/camel-openapi-java/src/generated/resources/META-INF/services/org/apache/camel/jmx-rest-definition-resolver
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.openapi.jmx.JmxRestDefinitionsResolver
diff --git a/components/camel-openapi-java/src/main/java/org/apache/camel/openapi/DefaultRestDefinitionsResolver.java b/components/camel-openapi-java/src/main/java/org/apache/camel/openapi/DefaultRestDefinitionsResolver.java
new file mode 100644
index 0000000..f1740d6
--- /dev/null
+++ b/components/camel-openapi-java/src/main/java/org/apache/camel/openapi/DefaultRestDefinitionsResolver.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.openapi;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.model.Model;
+import org.apache.camel.model.rest.RestDefinition;
+
+public class DefaultRestDefinitionsResolver implements RestDefinitionsResolver {
+
+    @Override
+    public List<RestDefinition> getRestDefinitions(CamelContext camelContext, String camelId) throws Exception {
+        if (camelId != null && !camelContext.getName().equals(camelId)) {
+            throw new UnsupportedOperationException("Must use JmxRestDefinitionsResolver to generate rest model from another CamelContext in the same JVM");
+        }
+
+        Model model = camelContext.getExtension(Model.class);
+        List<RestDefinition> rests = model.getRestDefinitions();
+        if (rests.isEmpty()) {
+            return null;
+        }
+        return rests;
+    }
+
+    @Override
+    public List<String> findCamelContexts() throws Exception {
+        return Collections.EMPTY_LIST;
+    }
+
+}
diff --git a/components/camel-openapi-java/src/main/java/org/apache/camel/openapi/RestDefinitionsResolver.java b/components/camel-openapi-java/src/main/java/org/apache/camel/openapi/RestDefinitionsResolver.java
new file mode 100644
index 0000000..ac89094
--- /dev/null
+++ b/components/camel-openapi-java/src/main/java/org/apache/camel/openapi/RestDefinitionsResolver.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.openapi;
+
+import java.util.List;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.model.rest.RestDefinition;
+
+/**
+ * Pluggable resolver for resolving rest and camel context either local or globally via JMX for the entire JVM
+ */
+public interface RestDefinitionsResolver {
+
+    String JMX_REST_DEFINITION_RESOLVER = "jmx-rest-definition-resolver";
+
+    List<RestDefinition> getRestDefinitions(CamelContext camelContext, String camelId) throws Exception;
+
+    List<String> findCamelContexts() throws Exception;
+
+}
diff --git a/components/camel-openapi-java/src/main/java/org/apache/camel/openapi/RestOpenApiProcessor.java b/components/camel-openapi-java/src/main/java/org/apache/camel/openapi/RestOpenApiProcessor.java
index feb355a..ccdfd2c 100644
--- a/components/camel-openapi-java/src/main/java/org/apache/camel/openapi/RestOpenApiProcessor.java
+++ b/components/camel-openapi-java/src/main/java/org/apache/camel/openapi/RestOpenApiProcessor.java
@@ -82,7 +82,7 @@ public class RestOpenApiProcessor implements Processor {
         try {
             // render list of camel contexts as root
             if (contextIdListing && (ObjectHelper.isEmpty(route) || route.equals("/"))) {
-                support.renderCamelContexts(adapter, contextId, contextIdPattern, json, yaml, configuration);
+                support.renderCamelContexts(exchange.getContext(), adapter, contextId, contextIdPattern, json, yaml, configuration);
             } else {
                 String name;
                 if (ObjectHelper.isNotEmpty(route)) {
diff --git a/components/camel-openapi-java/src/main/java/org/apache/camel/openapi/RestOpenApiSupport.java b/components/camel-openapi-java/src/main/java/org/apache/camel/openapi/RestOpenApiSupport.java
index 867f7d5..36bb325 100644
--- a/components/camel-openapi-java/src/main/java/org/apache/camel/openapi/RestOpenApiSupport.java
+++ b/components/camel-openapi-java/src/main/java/org/apache/camel/openapi/RestOpenApiSupport.java
@@ -16,8 +16,6 @@
  */
 package org.apache.camel.openapi;
 
-import java.io.InputStream;
-import java.lang.management.ManagementFactory;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.ArrayList;
@@ -25,13 +23,9 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import javax.management.MBeanServer;
-import javax.management.ObjectName;
-
 import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -49,10 +43,8 @@ import io.apicurio.datamodels.openapi.v3.models.Oas30License;
 import io.apicurio.datamodels.openapi.v3.models.Oas30Server;
 import org.apache.camel.CamelContext;
 import org.apache.camel.Exchange;
-import org.apache.camel.ExtendedCamelContext;
-import org.apache.camel.model.Model;
+import org.apache.camel.impl.engine.BaseServiceResolver;
 import org.apache.camel.model.rest.RestDefinition;
-import org.apache.camel.model.rest.RestsDefinition;
 import org.apache.camel.spi.ClassResolver;
 import org.apache.camel.spi.RestConfiguration;
 import org.apache.camel.support.PatternHelper;
@@ -63,6 +55,7 @@ import org.slf4j.LoggerFactory;
 
 
 import static org.apache.camel.openapi.OpenApiHelper.clearVendorExtensions;
+import static org.apache.camel.openapi.RestDefinitionsResolver.JMX_REST_DEFINITION_RESOLVER;
 
 /**
  * A support class for that allows SPI to plugin and offer OpenApi API service listings as part of the Camel
@@ -77,7 +70,9 @@ public class RestOpenApiSupport {
     static final String HEADER_HOST = "Host";
 
     private static final Logger LOG = LoggerFactory.getLogger(RestOpenApiSupport.class);
-    private RestOpenApiReader reader = new RestOpenApiReader();
+    private final RestOpenApiReader reader = new RestOpenApiReader();
+    private final RestDefinitionsResolver localRestDefinitionResolver = new DefaultRestDefinitionsResolver();
+    private volatile RestDefinitionsResolver jmxRestDefinitionResolver;
     private boolean cors;
 
     public void initOpenApi(BeanConfig openApiConfig, Map<String, Object> config) {
@@ -188,60 +183,20 @@ public class RestOpenApiSupport {
     }
 
     public List<RestDefinition> getRestDefinitions(CamelContext camelContext) throws Exception {
-        Model model = camelContext.getExtension(Model.class);
-        List<RestDefinition> rests = model.getRestDefinitions();
-        if (rests.isEmpty()) {
-            return null;
-        }
-        return rests;
+        return localRestDefinitionResolver.getRestDefinitions(camelContext, null);
     }
 
     public List<RestDefinition> getRestDefinitions(CamelContext camelContext, String camelId) throws Exception {
-        ObjectName found = null;
-
-        MBeanServer server = ManagementFactory.getPlatformMBeanServer();
-        Set<ObjectName> names = server.queryNames(new ObjectName("org.apache.camel:type=context,*"), null);
-        for (ObjectName on : names) {
-            String id = on.getKeyProperty("name");
-            if (id.startsWith("\"") && id.endsWith("\"")) {
-                id = id.substring(1, id.length() - 1);
-            }
-            if (camelId == null || camelId.equals(id)) {
-                found = on;
-            }
-        }
-
-        if (found != null) {
-            String xml = (String)server.invoke(found, "dumpRestsAsXml", new Object[] {true},
-                                            new String[] {"boolean"});
-            if (xml != null) {
-                LOG.debug("DumpRestAsXml:\n{}", xml);
-                InputStream xmlis = camelContext.getTypeConverter().convertTo(InputStream.class, xml);
-                ExtendedCamelContext ecc = camelContext.adapt(ExtendedCamelContext.class);
-                RestsDefinition rests = (RestsDefinition) ecc.getXMLRoutesDefinitionLoader().loadRestsDefinition(camelContext, xmlis);
-                if (rests != null) {
-                    return rests.getRests();
-                }
-            }
+        if (jmxRestDefinitionResolver == null) {
+            jmxRestDefinitionResolver = createJmxRestDefinitionsResolver(camelContext);
         }
-
-        return null;
+        return jmxRestDefinitionResolver.getRestDefinitions(camelContext, camelId);
     }
 
-    public List<String> findCamelContexts() throws Exception {
-        List<String> answer = new ArrayList<>();
-
-        MBeanServer server = ManagementFactory.getPlatformMBeanServer();
-        Set<ObjectName> names = server.queryNames(new ObjectName("*:type=context,*"), null);
-        for (ObjectName on : names) {
-
-            String id = on.getKeyProperty("name");
-            if (id.startsWith("\"") && id.endsWith("\"")) {
-                id = id.substring(1, id.length() - 1);
-            }
-            answer.add(id);
-        }
-        return answer;
+    protected RestDefinitionsResolver createJmxRestDefinitionsResolver(CamelContext camelContext) {
+        return new BaseServiceResolver<>(JMX_REST_DEFINITION_RESOLVER, RestDefinitionsResolver.class)
+                .resolve(camelContext)
+                .orElseThrow(() -> new IllegalArgumentException("Cannot find JMX_REST_DEFINITION_RESOLVER on classpath."));
     }
 
     public void renderResourceListing(CamelContext camelContext, RestApiResponseAdapter response,
@@ -323,7 +278,7 @@ public class RestOpenApiSupport {
     /**
      * Renders a list of available CamelContexts in the JVM
      */
-    public void renderCamelContexts(RestApiResponseAdapter response, String contextId,
+    public void renderCamelContexts(CamelContext camelContext, RestApiResponseAdapter response, String contextId,
                                     String contextIdPattern, boolean json, boolean yaml,
                                     RestConfiguration configuration)
         throws Exception {
@@ -333,7 +288,7 @@ public class RestOpenApiSupport {
             setupCorsHeaders(response, configuration.getCorsHeaders());
         }
 
-        List<String> contexts = findCamelContexts();
+        List<String> contexts = findCamelContexts(camelContext);
 
         // filter non matched CamelContext's
         if (contextIdPattern != null) {
@@ -382,6 +337,13 @@ public class RestOpenApiSupport {
         response.writeBytes(sb.toString().getBytes());
     }
 
+    private List<String> findCamelContexts(CamelContext camelContext) throws Exception {
+        if (jmxRestDefinitionResolver == null) {
+            jmxRestDefinitionResolver = createJmxRestDefinitionsResolver(camelContext);
+        }
+        return jmxRestDefinitionResolver.findCamelContexts();
+    }
+
     private static void setupCorsHeaders(RestApiResponseAdapter response, Map<String, String> corsHeaders) {
         // use default value if none has been configured
         String allowOrigin = corsHeaders != null ? corsHeaders.get("Access-Control-Allow-Origin") : null;
diff --git a/components/camel-openapi-java/src/main/java/org/apache/camel/openapi/jmx/JmxRestDefinitionsResolver.java b/components/camel-openapi-java/src/main/java/org/apache/camel/openapi/jmx/JmxRestDefinitionsResolver.java
new file mode 100644
index 0000000..d2ce04d
--- /dev/null
+++ b/components/camel-openapi-java/src/main/java/org/apache/camel/openapi/jmx/JmxRestDefinitionsResolver.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.openapi.jmx;
+
+import java.io.InputStream;
+import java.lang.management.ManagementFactory;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.model.rest.RestDefinition;
+import org.apache.camel.model.rest.RestsDefinition;
+import org.apache.camel.openapi.RestDefinitionsResolver;
+import org.apache.camel.openapi.RestOpenApiSupport;
+import org.apache.camel.spi.annotations.JdkService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.camel.openapi.RestDefinitionsResolver.JMX_REST_DEFINITION_RESOLVER;
+
+/**
+ * Resolves from JMX.
+ */
+@JdkService(JMX_REST_DEFINITION_RESOLVER)
+public class JmxRestDefinitionsResolver implements RestDefinitionsResolver {
+
+    private static final Logger LOG = LoggerFactory.getLogger(RestOpenApiSupport.class);
+
+    @Override
+    public List<RestDefinition> getRestDefinitions(CamelContext camelContext, String camelId) throws Exception {
+        ObjectName found = null;
+
+        MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+        Set<ObjectName> names = server.queryNames(new ObjectName("org.apache.camel:type=context,*"), null);
+        for (ObjectName on : names) {
+            String id = on.getKeyProperty("name");
+            if (id.startsWith("\"") && id.endsWith("\"")) {
+                id = id.substring(1, id.length() - 1);
+            }
+            if (camelId == null || camelId.equals(id)) {
+                found = on;
+            }
+        }
+
+        if (found != null) {
+            String xml = (String) server.invoke(found, "dumpRestsAsXml", new Object[]{true},
+                    new String[]{"boolean"});
+            if (xml != null) {
+                LOG.debug("DumpRestAsXml:\n{}", xml);
+                InputStream xmlis = camelContext.getTypeConverter().convertTo(InputStream.class, xml);
+                ExtendedCamelContext ecc = camelContext.adapt(ExtendedCamelContext.class);
+                RestsDefinition rests = (RestsDefinition) ecc.getXMLRoutesDefinitionLoader().loadRestsDefinition(camelContext, xmlis);
+                if (rests != null) {
+                    return rests.getRests();
+                }
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    public List<String> findCamelContexts() throws Exception {
+        List<String> answer = new ArrayList<>();
+
+        MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+        Set<ObjectName> names = server.queryNames(new ObjectName("*:type=context,*"), null);
+        for (ObjectName on : names) {
+
+            String id = on.getKeyProperty("name");
+            if (id.startsWith("\"") && id.endsWith("\"")) {
+                id = id.substring(1, id.length() - 1);
+            }
+            answer.add(id);
+        }
+        return answer;
+    }
+
+}
\ No newline at end of file