CAMEL-9687: Dump route/rests from JMX now support resolving property placeholders. Needed in camel-swagger-java so the rest api is presented with resolved values.
Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/e83d737e Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/e83d737e Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/e83d737e Branch: refs/heads/camel-2.16.x Commit: e83d737e440548ec98b5ca2e407117b79905609c Parents: 2264701 Author: Claus Ibsen <davscl...@apache.org> Authored: Wed Mar 9 21:02:57 2016 +0100 Committer: Claus Ibsen <davscl...@apache.org> Committed: Thu Mar 10 08:06:31 2016 +0100 ---------------------------------------------------------------------- .../mbean/ManagedCamelContextMBean.java | 6 + .../api/management/mbean/ManagedRouteMBean.java | 3 + .../management/mbean/ManagedCamelContext.java | 73 ++++++- .../camel/management/mbean/ManagedRoute.java | 40 +++- .../camel/model/RouteDefinitionHelper.java | 1 - .../apache/camel/util/XmlLineNumberParser.java | 192 +++++++++++++++++++ .../ManagedFromRestPlaceholderTest.java | 119 ++++++++++++ ...nagedRouteDumpRouteAsXmlPlaceholderTest.java | 96 ++++++++++ .../org/apache/camel/management/rest.properties | 22 +++ .../camel/swagger/RestSwaggerSupport.java | 11 +- ...estSwaggerReaderPropertyPlaceholderTest.java | 108 +++++++++++ 11 files changed, 665 insertions(+), 6 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/e83d737e/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedCamelContextMBean.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedCamelContextMBean.java b/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedCamelContextMBean.java index 4cb8905..d71472e 100644 --- a/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedCamelContextMBean.java +++ b/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedCamelContextMBean.java @@ -178,9 +178,15 @@ public interface ManagedCamelContextMBean extends ManagedPerformanceCounterMBean @ManagedOperation(description = "Dumps the rests as XML") String dumpRestsAsXml() throws Exception; + @ManagedOperation(description = "Dumps the rests as XML") + String dumpRestsAsXml(boolean resolvePlaceholders) throws Exception; + @ManagedOperation(description = "Dumps the routes as XML") String dumpRoutesAsXml() throws Exception; + @ManagedOperation(description = "Dumps the routes as XML") + String dumpRoutesAsXml(boolean resolvePlaceholders) throws Exception; + @ManagedOperation(description = "Adds or updates existing routes from XML") void addOrUpdateRoutesFromXml(String xml) throws Exception; http://git-wip-us.apache.org/repos/asf/camel/blob/e83d737e/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedRouteMBean.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedRouteMBean.java b/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedRouteMBean.java index 9d9e9b8..bdc26f7 100644 --- a/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedRouteMBean.java +++ b/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedRouteMBean.java @@ -102,6 +102,9 @@ public interface ManagedRouteMBean extends ManagedPerformanceCounterMBean { @ManagedOperation(description = "Dumps the route as XML") String dumpRouteAsXml() throws Exception; + @ManagedOperation(description = "Dumps the route as XML") + String dumpRouteAsXml(boolean resolvePlaceholders) throws Exception; + @ManagedOperation(description = "Updates the route from XML") void updateRouteFromXml(String xml) throws Exception; http://git-wip-us.apache.org/repos/asf/camel/blob/e83d737e/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java b/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java index 91ffac0..c69169a 100644 --- a/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java +++ b/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java @@ -29,6 +29,7 @@ import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.management.openmbean.CompositeData; @@ -63,7 +64,7 @@ import org.apache.camel.spi.ManagementStrategy; import org.apache.camel.util.CamelContextHelper; import org.apache.camel.util.JsonSchemaHelper; import org.apache.camel.util.ObjectHelper; - +import org.apache.camel.util.XmlLineNumberParser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -348,6 +349,11 @@ public class ManagedCamelContext extends ManagedPerformanceCounter implements Ti } public String dumpRestsAsXml() throws Exception { + return dumpRestsAsXml(false); + } + + @Override + public String dumpRestsAsXml(boolean resolvePlaceholders) throws Exception { List<RestDefinition> rests = context.getRestDefinitions(); if (rests.isEmpty()) { return null; @@ -356,10 +362,43 @@ public class ManagedCamelContext extends ManagedPerformanceCounter implements Ti // use a routes definition to dump the rests RestsDefinition def = new RestsDefinition(); def.setRests(rests); - return ModelHelper.dumpModelAsXml(context, def); + String xml = ModelHelper.dumpModelAsXml(context, def); + + if (resolvePlaceholders) { + final AtomicBoolean changed = new AtomicBoolean(); + InputStream is = new ByteArrayInputStream(xml.getBytes()); + Document dom = XmlLineNumberParser.parseXml(is, new XmlLineNumberParser.XmlTextTransformer() { + @Override + public String transform(String text) { + try { + String after = getContext().resolvePropertyPlaceholders(text); + if (!changed.get()) { + changed.set(!text.equals(after)); + } + return after; + } catch (Exception e) { + // ignore + return text; + } + } + }); + // okay there were some property placeholder replaced so re-create the model + if (changed.get()) { + xml = context.getTypeConverter().mandatoryConvertTo(String.class, dom); + RestsDefinition copy = ModelHelper.createModelFromXml(context, xml, RestsDefinition.class); + xml = ModelHelper.dumpModelAsXml(context, copy); + } + } + + return xml; } public String dumpRoutesAsXml() throws Exception { + return dumpRoutesAsXml(false); + } + + @Override + public String dumpRoutesAsXml(boolean resolvePlaceholders) throws Exception { List<RouteDefinition> routes = context.getRouteDefinitions(); if (routes.isEmpty()) { return null; @@ -368,7 +407,35 @@ public class ManagedCamelContext extends ManagedPerformanceCounter implements Ti // use a routes definition to dump the routes RoutesDefinition def = new RoutesDefinition(); def.setRoutes(routes); - return ModelHelper.dumpModelAsXml(context, def); + String xml = ModelHelper.dumpModelAsXml(context, def); + + if (resolvePlaceholders) { + final AtomicBoolean changed = new AtomicBoolean(); + InputStream is = new ByteArrayInputStream(xml.getBytes()); + Document dom = XmlLineNumberParser.parseXml(is, new XmlLineNumberParser.XmlTextTransformer() { + @Override + public String transform(String text) { + try { + String after = getContext().resolvePropertyPlaceholders(text); + if (!changed.get()) { + changed.set(!text.equals(after)); + } + return after; + } catch (Exception e) { + // ignore + return text; + } + } + }); + // okay there were some property placeholder replaced so re-create the model + if (changed.get()) { + xml = context.getTypeConverter().mandatoryConvertTo(String.class, dom); + RoutesDefinition copy = ModelHelper.createModelFromXml(context, xml, RoutesDefinition.class); + xml = ModelHelper.dumpModelAsXml(context, copy); + } + } + + return xml; } public void addOrUpdateRoutesFromXml(String xml) throws Exception { http://git-wip-us.apache.org/repos/asf/camel/blob/e83d737e/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedRoute.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedRoute.java b/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedRoute.java index 47760f3..837d798 100644 --- a/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedRoute.java +++ b/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedRoute.java @@ -16,6 +16,8 @@ */ package org.apache.camel.management.mbean; +import java.io.ByteArrayInputStream; +import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -26,6 +28,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import javax.management.AttributeValueExp; import javax.management.MBeanServer; import javax.management.ObjectName; @@ -33,6 +36,8 @@ import javax.management.Query; import javax.management.QueryExp; import javax.management.StringValueExp; +import org.w3c.dom.Document; + import org.apache.camel.CamelContext; import org.apache.camel.Exchange; import org.apache.camel.ManagementStatisticsLevel; @@ -48,6 +53,7 @@ import org.apache.camel.model.RouteDefinition; import org.apache.camel.spi.ManagementStrategy; import org.apache.camel.spi.RoutePolicy; import org.apache.camel.util.ObjectHelper; +import org.apache.camel.util.XmlLineNumberParser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -256,10 +262,42 @@ public class ManagedRoute extends ManagedPerformanceCounter implements TimerList } public String dumpRouteAsXml() throws Exception { + return dumpRouteAsXml(false); + } + + @Override + public String dumpRouteAsXml(boolean resolvePlaceholders) throws Exception { String id = route.getId(); RouteDefinition def = context.getRouteDefinition(id); if (def != null) { - return ModelHelper.dumpModelAsXml(context, def); + String xml = ModelHelper.dumpModelAsXml(context, def); + + if (resolvePlaceholders) { + final AtomicBoolean changed = new AtomicBoolean(); + InputStream is = new ByteArrayInputStream(xml.getBytes()); + Document dom = XmlLineNumberParser.parseXml(is, new XmlLineNumberParser.XmlTextTransformer() { + @Override + public String transform(String text) { + try { + String after = getContext().resolvePropertyPlaceholders(text); + if (!changed.get()) { + changed.set(!text.equals(after)); + } + return after; + } catch (Exception e) { + // ignore + return text; + } + } + }); + // okay there were some property placeholder replaced so re-create the model + if (changed.get()) { + xml = context.getTypeConverter().mandatoryConvertTo(String.class, dom); + RouteDefinition copy = ModelHelper.createModelFromXml(context, xml, RouteDefinition.class); + xml = ModelHelper.dumpModelAsXml(context, copy); + } + } + return xml; } return null; } http://git-wip-us.apache.org/repos/asf/camel/blob/e83d737e/camel-core/src/main/java/org/apache/camel/model/RouteDefinitionHelper.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/model/RouteDefinitionHelper.java b/camel-core/src/main/java/org/apache/camel/model/RouteDefinitionHelper.java index a60bc5c..0d6666e 100644 --- a/camel-core/src/main/java/org/apache/camel/model/RouteDefinitionHelper.java +++ b/camel-core/src/main/java/org/apache/camel/model/RouteDefinitionHelper.java @@ -383,7 +383,6 @@ public final class RouteDefinitionHelper { } } - private static void initParentAndErrorHandlerBuilder(ModelCamelContext context, RouteDefinition route, List<ProcessorDefinition<?>> abstracts, List<OnExceptionDefinition> onExceptions) { http://git-wip-us.apache.org/repos/asf/camel/blob/e83d737e/camel-core/src/main/java/org/apache/camel/util/XmlLineNumberParser.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/util/XmlLineNumberParser.java b/camel-core/src/main/java/org/apache/camel/util/XmlLineNumberParser.java new file mode 100644 index 0000000..2eb1a28 --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/util/XmlLineNumberParser.java @@ -0,0 +1,192 @@ +/** + * 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.util; + +import java.io.IOException; +import java.io.InputStream; +import java.io.StringReader; +import java.util.Stack; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +/** + * An XML parser that uses SAX to include line and column number for each XML element in the parsed Document. + * <p> + * The line number and column number can be obtained from a Node/Element using + * <pre> + * String lineNumber = (String) node.getUserData(XmlLineNumberParser.LINE_NUMBER); + * String lineNumberEnd = (String) node.getUserData(XmlLineNumberParser.LINE_NUMBER_END); + * String columnNumber = (String) node.getUserData(XmlLineNumberParser.COLUMN_NUMBER); + * String columnNumberEnd = (String) node.getUserData(XmlLineNumberParser.COLUMN_NUMBER_END); + * </pre> + */ +public final class XmlLineNumberParser { + + public static final String LINE_NUMBER = "lineNumber"; + public static final String COLUMN_NUMBER = "colNumber"; + public static final String LINE_NUMBER_END = "lineNumberEnd"; + public static final String COLUMN_NUMBER_END = "colNumberEnd"; + + /** + * Allows to plugin a custom text transformer in the parser, that can transform all the text content + */ + public interface XmlTextTransformer { + + String transform(String text); + + } + + private XmlLineNumberParser() { + } + + /** + * Parses the XML. + * + * @param is the XML content as an input stream + * @return the DOM model + * @throws Exception is thrown if error parsing + */ + public static Document parseXml(final InputStream is) throws Exception { + return parseXml(is, new NoopTransformer()); + } + + /** + * Parses the XML. + * + * @param is the XML content as an input stream + * @return the DOM model + * @throws Exception is thrown if error parsing + */ + public static Document parseXml(final InputStream is, final XmlTextTransformer transformer) throws Exception { + ObjectHelper.notNull(is, "is"); + ObjectHelper.notNull(transformer, "transformer"); + + final Document doc; + SAXParser parser; + final SAXParserFactory factory = SAXParserFactory.newInstance(); + parser = factory.newSAXParser(); + final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + // turn off validator and loading external dtd + dbf.setValidating(false); + dbf.setNamespaceAware(true); + dbf.setFeature("http://xml.org/sax/features/namespaces", false); + dbf.setFeature("http://xml.org/sax/features/validation", false); + dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false); + dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + dbf.setFeature("http://xml.org/sax/features/external-general-entities", false); + final DocumentBuilder docBuilder = dbf.newDocumentBuilder(); + doc = docBuilder.newDocument(); + + final Stack<Element> elementStack = new Stack<Element>(); + final StringBuilder textBuffer = new StringBuilder(); + final DefaultHandler handler = new DefaultHandler() { + private Locator locator; + private boolean found; + + @Override + public void setDocumentLocator(final Locator locator) { + this.locator = locator; // Save the locator, so that it can be used later for line tracking when traversing nodes. + } + + @Override + public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) throws SAXException { + addTextIfNeeded(); + + Element el = doc.createElement(qName); + + for (int i = 0; i < attributes.getLength(); i++) { + el.setAttribute(transformer.transform(attributes.getQName(i)), transformer.transform(attributes.getValue(i))); + } + + el.setUserData(LINE_NUMBER, String.valueOf(this.locator.getLineNumber()), null); + el.setUserData(COLUMN_NUMBER, String.valueOf(this.locator.getColumnNumber()), null); + elementStack.push(el); + } + + @Override + public void endElement(final String uri, final String localName, final String qName) { + addTextIfNeeded(); + + final Element closedEl = elementStack.isEmpty() ? null : elementStack.pop(); + if (closedEl != null) { + if (elementStack.isEmpty()) { + // Is this the root element? + doc.appendChild(closedEl); + } else { + final Element parentEl = elementStack.peek(); + parentEl.appendChild(closedEl); + } + + closedEl.setUserData(LINE_NUMBER_END, String.valueOf(this.locator.getLineNumber()), null); + closedEl.setUserData(COLUMN_NUMBER_END, String.valueOf(this.locator.getColumnNumber()), null); + } + } + + @Override + public void characters(final char ch[], final int start, final int length) throws SAXException { + char[] chars = new char[length]; + System.arraycopy(ch, start, chars, 0, length); + String s = new String(chars); + s = transformer.transform(s); + textBuffer.append(s); + } + + @Override + public InputSource resolveEntity(String publicId, String systemId) throws IOException, SAXException { + // do not resolve external dtd + return new InputSource(new StringReader("")); + } + + // Outputs text accumulated under the current node + private void addTextIfNeeded() { + if (textBuffer.length() > 0) { + final Element el = elementStack.isEmpty() ? null : elementStack.peek(); + if (el != null) { + final Node textNode = doc.createTextNode(textBuffer.toString()); + el.appendChild(textNode); + textBuffer.delete(0, textBuffer.length()); + } + } + } + }; + parser.parse(is, handler); + + return doc; + } + + private static final class NoopTransformer implements XmlTextTransformer { + + @Override + public String transform(String text) { + return text; + } + + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/e83d737e/camel-core/src/test/java/org/apache/camel/management/ManagedFromRestPlaceholderTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/management/ManagedFromRestPlaceholderTest.java b/camel-core/src/test/java/org/apache/camel/management/ManagedFromRestPlaceholderTest.java new file mode 100644 index 0000000..40d4057 --- /dev/null +++ b/camel-core/src/test/java/org/apache/camel/management/ManagedFromRestPlaceholderTest.java @@ -0,0 +1,119 @@ +/** + * 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.management; + +import java.util.Arrays; +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import org.apache.camel.CamelContext; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.properties.PropertiesComponent; +import org.apache.camel.component.rest.DummyRestConsumerFactory; +import org.apache.camel.impl.DefaultCamelContext; +import org.apache.camel.impl.SimpleRegistry; +import org.apache.camel.model.rest.CollectionFormat; +import org.apache.camel.model.rest.RestParamType; + +public class ManagedFromRestPlaceholderTest extends ManagementTestSupport { + + @Override + protected CamelContext createCamelContext() throws Exception { + SimpleRegistry registry = new SimpleRegistry(); + registry.put("dummy-test", new DummyRestConsumerFactory()); + + CamelContext answer = new DefaultCamelContext(registry); + + PropertiesComponent pc = new PropertiesComponent(); + pc.setLocation("classpath:org/apache/camel/management/rest.properties"); + answer.addComponent("properties", pc); + + return answer; + } + + public void testFromRestModelPlaceholder() throws Exception { + // JMX tests dont work well on AIX CI servers (hangs them) + if (isPlatform("aix")) { + return; + } + + MBeanServer mbeanServer = getMBeanServer(); + + ObjectName on = ObjectName.getInstance("org.apache.camel:context=camel-1,type=context,name=\"camel-1\""); + + String xml = (String) mbeanServer.invoke(on, "dumpRestsAsXml", new Object[]{true}, new String[]{"boolean"}); + assertNotNull(xml); + log.info(xml); + + assertTrue(xml.contains("<rests")); + assertTrue(xml.contains("<rest path=\"/say/hello\">")); + assertTrue(xml.contains("<rest path=\"/say/bye\">")); + assertTrue(xml.contains("</rest>")); + assertTrue(xml.contains("<get")); + assertTrue(xml.contains("application/json")); + assertTrue(xml.contains("<post")); + assertTrue(xml.contains("application/json")); + assertTrue(xml.contains("</rests>")); + + assertTrue(xml.contains("<param name=\"header_letter\" type=\"query\" description=\"header param description2\"" + + " defaultValue=\"b\" required=\"false\" collectionFormat=\"multi\" dataType=\"string\" access=\"acc2\">")); + assertTrue(xml.contains("<param name=\"header_count\" type=\"header\" description=\"header param description1\" " + + "defaultValue=\"1\" required=\"true\" dataType=\"integer\" access=\"acc1\">")); + assertTrue(xml.contains("<value>1</value>")); + assertTrue(xml.contains("<value>a</value>")); + + assertTrue(xml.contains("<responseMessage code=\"300\" message=\"test msg\" responseModel=\"java.lang.Integer\"/>")); + + String xml2 = (String) mbeanServer.invoke(on, "dumpRoutesAsXml", null, null); + log.info(xml2); + // and we should have rest in the routes that indicate its from a rest dsl + assertTrue(xml2.contains("rest=\"true\"")); + + // there should be 3 + 2 routes + assertEquals(3 + 2, context.getRouteDefinitions().size()); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + restConfiguration().host("localhost"); + rest("{{foo}}") + .get().to("direct:hello"); + + rest("{{bar}}") + .get().consumes("application/json") + .param().type(RestParamType.header).description("header param description1").dataType("integer").allowableValues(Arrays.asList("1", "2", "3", "4")) + .defaultValue("1").name("header_count").required(true).access("acc1") + .endParam(). + param().type(RestParamType.query).description("header param description2").dataType("string").allowableValues(Arrays.asList("a", "b", "c", "d")) + .defaultValue("b").collectionFormat(CollectionFormat.multi).name("header_letter").required(false).access("acc2") + .endParam() + .responseMessage().code(300).message("test msg").responseModel(Integer.class).endResponseMessage() + .to("direct:bye") + .post().to("mock:update"); + + from("direct:hello") + .transform().constant("Hello World"); + + from("direct:bye") + .transform().constant("Bye World"); + } + }; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e83d737e/camel-core/src/test/java/org/apache/camel/management/ManagedRouteDumpRouteAsXmlPlaceholderTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/management/ManagedRouteDumpRouteAsXmlPlaceholderTest.java b/camel-core/src/test/java/org/apache/camel/management/ManagedRouteDumpRouteAsXmlPlaceholderTest.java new file mode 100644 index 0000000..0bf976f --- /dev/null +++ b/camel-core/src/test/java/org/apache/camel/management/ManagedRouteDumpRouteAsXmlPlaceholderTest.java @@ -0,0 +1,96 @@ +/** + * 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.management; + +import java.util.Set; +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import org.apache.camel.CamelContext; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.component.properties.PropertiesComponent; +import org.apache.camel.component.rest.DummyRestConsumerFactory; +import org.apache.camel.impl.DefaultCamelContext; +import org.apache.camel.impl.SimpleRegistry; + +/** + * @version + */ +public class ManagedRouteDumpRouteAsXmlPlaceholderTest extends ManagementTestSupport { + + @Override + protected CamelContext createCamelContext() throws Exception { + CamelContext answer = super.createCamelContext(); + + PropertiesComponent pc = new PropertiesComponent(); + pc.setLocation("classpath:org/apache/camel/management/rest.properties"); + answer.addComponent("properties", pc); + + return answer; + } + + public void testDumpAsXml() throws Exception { + // JMX tests dont work well on AIX CI servers (hangs them) + if (isPlatform("aix")) { + return; + } + + MBeanServer mbeanServer = getMBeanServer(); + ObjectName on = getRouteObjectName(mbeanServer); + + MockEndpoint mock = getMockEndpoint("mock:result"); + mock.expectedBodiesReceived("Hello World"); + + template.sendBody("direct:start", "Hello World"); + + assertMockEndpointsSatisfied(); + + // should be started + String routeId = (String) mbeanServer.getAttribute(on, "RouteId"); + assertEquals("myRoute", routeId); + + String xml = (String) mbeanServer.invoke(on, "dumpRouteAsXml", new Object[]{true}, new String[]{"boolean"}); + assertNotNull(xml); + log.info(xml); + + assertTrue(xml.contains("direct:start")); + assertTrue(xml.contains("route")); + assertTrue(xml.contains("myRoute")); + assertTrue(xml.contains("mock:result")); + } + + static ObjectName getRouteObjectName(MBeanServer mbeanServer) throws Exception { + Set<ObjectName> set = mbeanServer.queryNames(new ObjectName("*:type=routes,*"), null); + assertEquals(1, set.size()); + + return set.iterator().next(); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("{{start}}").routeId("myRoute") + .log("Got ${body}") + .to("{{result}}"); + } + }; + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/e83d737e/camel-core/src/test/resources/org/apache/camel/management/rest.properties ---------------------------------------------------------------------- diff --git a/camel-core/src/test/resources/org/apache/camel/management/rest.properties b/camel-core/src/test/resources/org/apache/camel/management/rest.properties new file mode 100644 index 0000000..d00c3b1 --- /dev/null +++ b/camel-core/src/test/resources/org/apache/camel/management/rest.properties @@ -0,0 +1,22 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +foo=/say/hello +bar=/say/bye + +start=direct:start +result=mock:result \ No newline at end of file http://git-wip-us.apache.org/repos/asf/camel/blob/e83d737e/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/RestSwaggerSupport.java ---------------------------------------------------------------------- diff --git a/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/RestSwaggerSupport.java b/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/RestSwaggerSupport.java index 58aeb05..0017873 100644 --- a/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/RestSwaggerSupport.java +++ b/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/RestSwaggerSupport.java @@ -119,6 +119,7 @@ public class RestSwaggerSupport { public List<RestDefinition> getRestDefinitions(String camelId) throws Exception { ObjectName found = null; + boolean supportResolvePlaceholder = false; MBeanServer server = ManagementFactory.getPlatformMBeanServer(); Set<ObjectName> names = server.queryNames(new ObjectName("org.apache.camel:type=context,*"), null); @@ -133,11 +134,19 @@ public class RestSwaggerSupport { if (CamelVersionHelper.isGE("2.15.0", version)) { found = on; } + if (CamelVersionHelper.isGE("2.15.3", version)) { + supportResolvePlaceholder = true; + } } } if (found != null) { - String xml = (String) server.invoke(found, "dumpRestsAsXml", null, null); + String xml; + if (supportResolvePlaceholder) { + xml = (String) server.invoke(found, "dumpRestsAsXml", new Object[]{true}, new String[]{"boolean"}); + } else { + xml = (String) server.invoke(found, "dumpRestsAsXml", null, null); + } if (xml != null) { RestsDefinition rests = ModelHelper.createModelFromXml(null, xml, RestsDefinition.class); if (rests != null) { http://git-wip-us.apache.org/repos/asf/camel/blob/e83d737e/components/camel-swagger-java/src/test/java/org/apache/camel/swagger/RestSwaggerReaderPropertyPlaceholderTest.java ---------------------------------------------------------------------- diff --git a/components/camel-swagger-java/src/test/java/org/apache/camel/swagger/RestSwaggerReaderPropertyPlaceholderTest.java b/components/camel-swagger-java/src/test/java/org/apache/camel/swagger/RestSwaggerReaderPropertyPlaceholderTest.java new file mode 100644 index 0000000..a4ec368 --- /dev/null +++ b/components/camel-swagger-java/src/test/java/org/apache/camel/swagger/RestSwaggerReaderPropertyPlaceholderTest.java @@ -0,0 +1,108 @@ +/** + * 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.swagger; + +import java.util.List; +import java.util.Properties; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import io.swagger.jaxrs.config.BeanConfig; +import io.swagger.models.Swagger; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.impl.DefaultClassResolver; +import org.apache.camel.impl.JndiRegistry; +import org.apache.camel.model.rest.RestDefinition; +import org.apache.camel.model.rest.RestParamType; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.junit.Test; + +public class RestSwaggerReaderPropertyPlaceholderTest extends CamelTestSupport { + + @Override + protected boolean useJmx() { + return true; + } + + @Override + protected JndiRegistry createRegistry() throws Exception { + JndiRegistry jndi = super.createRegistry(); + jndi.bind("dummy-rest", new DummyRestConsumerFactory()); + return jndi; + } + + @Override + protected Properties useOverridePropertiesWithPropertiesComponent() { + Properties prop = new Properties(); + prop.put("foo", "hello"); + prop.put("bar", "bye"); + return prop; + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + rest("/{{foo}}").consumes("application/json").produces("application/json") + .get("/hi/{name}").description("Saying hi") + .param().name("name").type(RestParamType.path).dataType("string").description("Who is it").endParam() + .to("log:hi") + .get("/{{bar}}/{name}").description("Saying bye") + .param().name("name").type(RestParamType.path).dataType("string").description("Who is it").endParam() + .responseMessage().code(200).message("A reply message").endResponseMessage() + .to("log:bye") + .post("/{{bar}}").description("To update the greeting message").consumes("application/xml").produces("application/xml") + .param().name("greeting").type(RestParamType.body).dataType("string").description("Message to use as greeting").endParam() + .to("log:bye"); + } + }; + } + + @Test + public void testReaderRead() throws Exception { + BeanConfig config = new BeanConfig(); + config.setHost("localhost:8080"); + config.setSchemes(new String[]{"http"}); + config.setBasePath("/api"); + RestSwaggerReader reader = new RestSwaggerReader(); + + RestSwaggerSupport support = new RestSwaggerSupport(); + List<RestDefinition> rests = support.getRestDefinitions(context.getName()); + + Swagger swagger = reader.read(rests, null, config, context.getName(), new DefaultClassResolver()); + assertNotNull(swagger); + + ObjectMapper mapper = new ObjectMapper(); + mapper.enable(SerializationFeature.INDENT_OUTPUT); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + String json = mapper.writeValueAsString(swagger); + + log.info(json); + + assertTrue(json.contains("\"host\" : \"localhost:8080\"")); + assertTrue(json.contains("\"basePath\" : \"/api\"")); + assertTrue(json.contains("\"/hello/bye\"")); + assertTrue(json.contains("\"summary\" : \"To update the greeting message\"")); + assertTrue(json.contains("\"/hello/bye/{name}\"")); + assertTrue(json.contains("\"/hello/hi/{name}\"")); + + context.stop(); + } + +}