diff --git a/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedComponentMBean.java b/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedComponentMBean.java index 60f065e48bf9a..0b1c9a716f486 100644 --- a/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedComponentMBean.java +++ b/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedComponentMBean.java @@ -29,4 +29,7 @@ public interface ManagedComponentMBean { @ManagedAttribute(description = "Camel ID") String getCamelId(); + @ManagedAttribute(description = "Camel ManagementName") + String getCamelManagementName(); + } \ No newline at end of file diff --git a/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedEndpointMBean.java b/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedEndpointMBean.java index 6b9c9b8ae9754..69206b6e32020 100644 --- a/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedEndpointMBean.java +++ b/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedEndpointMBean.java @@ -23,6 +23,9 @@ public interface ManagedEndpointMBean { @ManagedAttribute(description = "Camel ID") String getCamelId(); + @ManagedAttribute(description = "Camel ManagementName") + String getCamelManagementName(); + @ManagedAttribute(description = "Endpoint URI", mask = true) String getEndpointUri(); diff --git a/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedErrorHandlerMBean.java b/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedErrorHandlerMBean.java index 9d0c95cc4f471..56ed78d7fdada 100644 --- a/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedErrorHandlerMBean.java +++ b/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedErrorHandlerMBean.java @@ -23,6 +23,9 @@ public interface ManagedErrorHandlerMBean { @ManagedAttribute(description = "Camel ID") String getCamelId(); + @ManagedAttribute(description = "Camel ManagementName") + String getCamelManagementName(); + @ManagedAttribute(description = "Does the error handler support redelivery") boolean isSupportRedelivery(); diff --git a/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedProcessorMBean.java b/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedProcessorMBean.java index f31ed70a8b879..eaf16d5363b3f 100644 --- a/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedProcessorMBean.java +++ b/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedProcessorMBean.java @@ -27,6 +27,9 @@ public interface ManagedProcessorMBean extends ManagedPerformanceCounterMBean { @ManagedAttribute(description = "Camel ID") String getCamelId(); + @ManagedAttribute(description = "Camel ManagementName") + String getCamelManagementName(); + @ManagedAttribute(description = "Route ID") String getRouteId(); diff --git a/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedResourceEndpointMBean.java b/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedResourceEndpointMBean.java index dbe54faaf02ec..26601e9eb3a34 100644 --- a/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedResourceEndpointMBean.java +++ b/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedResourceEndpointMBean.java @@ -21,6 +21,15 @@ public interface ManagedResourceEndpointMBean { + @ManagedAttribute(description = "Camel context ID") + String getCamelId(); + + @ManagedAttribute(description = "Camel ManagementName") + String getCamelManagementName(); + + @ManagedAttribute(description = "Endpoint service state") + String getState(); + @ManagedAttribute(description = "Whether the content is cached") boolean isContentCache(); 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 7f90e12033075..0fb7ff0cad07f 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 @@ -39,6 +39,9 @@ public interface ManagedRouteMBean extends ManagedPerformanceCounterMBean { @ManagedAttribute(description = "Camel ID") String getCamelId(); + @ManagedAttribute(description = "Camel ManagementName") + String getCamelManagementName(); + @ManagedAttribute(description = "Tracing") Boolean getTracing(); diff --git a/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedServiceMBean.java b/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedServiceMBean.java index 7f04c842ff154..0ef03d101fbd7 100644 --- a/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedServiceMBean.java +++ b/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedServiceMBean.java @@ -27,6 +27,9 @@ public interface ManagedServiceMBean { @ManagedAttribute(description = "Camel ID") String getCamelId(); + @ManagedAttribute(description = "Camel ManagementName") + String getCamelManagementName(); + @ManagedAttribute(description = "Route ID") String getRouteId(); diff --git a/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java b/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java index 33bffd92206cb..c4e0de7c0b3f9 100644 --- a/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java +++ b/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java @@ -899,6 +899,22 @@ public String toString() { }; } + /** + * Returns the expression for the {@code null} value + */ + public static Expression nullExpression() { + return new ExpressionAdapter() { + public Object evaluate(Exchange exchange) { + return null; + } + + @Override + public String toString() { + return "null"; + } + }; + } + /** * Returns the expression for the exchanges inbound message body converted * to the given type. diff --git a/camel-core/src/main/java/org/apache/camel/component/ResourceEndpoint.java b/camel-core/src/main/java/org/apache/camel/component/ResourceEndpoint.java index 9b3af1d7c8910..8060c403c9c3f 100644 --- a/camel-core/src/main/java/org/apache/camel/component/ResourceEndpoint.java +++ b/camel-core/src/main/java/org/apache/camel/component/ResourceEndpoint.java @@ -111,6 +111,21 @@ public boolean isContentCacheCleared() { return buffer == null; } + @ManagedAttribute(description = "Camel context ID") + public String getCamelId() { + return getCamelContext().getName(); + } + + @ManagedAttribute(description = "Camel ManagementName") + public String getCamelManagementName() { + return getCamelContext().getManagementName(); + } + + @ManagedAttribute(description = "Endpoint service state") + public String getState() { + return getStatus().name(); + } + /** * Sets whether to use resource content cache or not - default is false. * diff --git a/camel-core/src/main/java/org/apache/camel/component/seda/SedaEndpoint.java b/camel-core/src/main/java/org/apache/camel/component/seda/SedaEndpoint.java index f2c5fca7d6366..9d4ade2d90263 100644 --- a/camel-core/src/main/java/org/apache/camel/component/seda/SedaEndpoint.java +++ b/camel-core/src/main/java/org/apache/camel/component/seda/SedaEndpoint.java @@ -415,11 +415,16 @@ public String browseRangeMessagesAsXml(Integer fromIndex, Integer toIndex, Boole return EndpointHelper.browseRangeMessagesAsXml(this, fromIndex, toIndex, includeBody); } - @ManagedAttribute(description = "Camel context name") + @ManagedAttribute(description = "Camel context ID") public String getCamelId() { return getCamelContext().getName(); } + @ManagedAttribute(description = "Camel ManagementName") + public String getCamelManagementName() { + return getCamelContext().getManagementName(); + } + @ManagedAttribute(description = "Endpoint service state") public String getState() { return getStatus().name(); diff --git a/camel-core/src/main/java/org/apache/camel/component/timer/TimerEndpoint.java b/camel-core/src/main/java/org/apache/camel/component/timer/TimerEndpoint.java index 61e3b880638ee..5b4dc3f8afc2f 100644 --- a/camel-core/src/main/java/org/apache/camel/component/timer/TimerEndpoint.java +++ b/camel-core/src/main/java/org/apache/camel/component/timer/TimerEndpoint.java @@ -184,6 +184,11 @@ public String getCamelId() { return this.getCamelContext().getName(); } + @ManagedAttribute(description = "Camel ManagementName") + public String getCamelManagementName() { + return this.getCamelContext().getManagementName(); + } + @ManagedAttribute(description = "Endpoint Uri") public String getEndpointUri() { return super.getEndpointUri(); diff --git a/camel-core/src/main/java/org/apache/camel/component/xslt/XsltEndpoint.java b/camel-core/src/main/java/org/apache/camel/component/xslt/XsltEndpoint.java index aa91b1a0d05eb..f6f505c5eefb2 100644 --- a/camel-core/src/main/java/org/apache/camel/component/xslt/XsltEndpoint.java +++ b/camel-core/src/main/java/org/apache/camel/component/xslt/XsltEndpoint.java @@ -68,6 +68,11 @@ public String getCamelId() { return getCamelContext().getName(); } + @ManagedAttribute(description = "Camel ManagementName") + public String getCamelManagementName() { + return getCamelContext().getManagementName(); + } + public XsltEndpoint findOrCreateEndpoint(String uri, String newResourceUri) { String newUri = uri.replace(resourceUri, newResourceUri); LOG.trace("Getting endpoint with URI: {}", newUri); diff --git a/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContextNameStrategy.java b/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContextNameStrategy.java index f7fec6c1c1d8f..ef5b95b657f28 100644 --- a/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContextNameStrategy.java +++ b/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContextNameStrategy.java @@ -59,6 +59,7 @@ public boolean isFixedName() { } public static int getNextCounter() { + // we want to start counting from 1, so increment first return CONTEXT_COUNTER.incrementAndGet(); } diff --git a/camel-core/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java b/camel-core/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java index 68da7b87270cd..985857acf1e7c 100644 --- a/camel-core/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java +++ b/camel-core/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java @@ -317,6 +317,8 @@ private Expression createSimpleExpressionDirectly(String expression) { return ExpressionBuilder.camelContextNameExpression(); } else if (ObjectHelper.equal(expression, "routeId")) { return ExpressionBuilder.routeIdExpression(); + } else if (ObjectHelper.equal(expression, "null")) { + return ExpressionBuilder.nullExpression(); } return null; diff --git a/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedComponent.java b/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedComponent.java index b301d6657c70b..16963915dd5e8 100644 --- a/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedComponent.java +++ b/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedComponent.java @@ -64,6 +64,10 @@ public String getCamelId() { return component.getCamelContext().getName(); } + public String getCamelManagementName() { + return component.getCamelContext().getManagementName(); + } + public Object getInstance() { return component; } diff --git a/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedEndpoint.java b/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedEndpoint.java index 83771a40ddbf3..deffddf88e40c 100644 --- a/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedEndpoint.java +++ b/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedEndpoint.java @@ -45,6 +45,11 @@ public String getCamelId() { return endpoint.getCamelContext().getName(); } + @Override + public String getCamelManagementName() { + return endpoint.getCamelContext().getManagementName(); + } + @Override public String getEndpointUri() { return endpoint.getEndpointUri(); diff --git a/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedErrorHandler.java b/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedErrorHandler.java index 69cb4bf9b792b..d4fe005789f81 100644 --- a/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedErrorHandler.java +++ b/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedErrorHandler.java @@ -61,6 +61,10 @@ public String getCamelId() { return routeContext.getCamelContext().getName(); } + public String getCamelManagementName() { + return routeContext.getCamelContext().getManagementName(); + } + public boolean isSupportRedelivery() { return errorHandler instanceof RedeliveryErrorHandler; } diff --git a/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedProcessor.java b/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedProcessor.java index 885bc3b83aab6..c3d6dd3a8987f 100644 --- a/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedProcessor.java +++ b/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedProcessor.java @@ -93,6 +93,10 @@ public String getCamelId() { return context.getName(); } + public String getCamelManagementName() { + return context.getManagementName(); + } + public String getRouteId() { if (route != null) { return route.getId(); 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 1c6495aabdcd7..b1cc98448442b 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 @@ -108,6 +108,10 @@ public String getCamelId() { return context.getName(); } + public String getCamelManagementName() { + return context.getManagementName(); + } + public Boolean getTracing() { return route.getRouteContext().isTracing(); } @@ -232,7 +236,7 @@ public void updateRouteFromXml(String xml) throws Exception { public String dumpRouteStatsAsXml(boolean fullStats, boolean includeProcessors) throws Exception { // in this logic we need to calculate the accumulated processing time for the processor in the route - // and hence why the logic is a bit more complicated to do this, as we need to caculate that from + // and hence why the logic is a bit more complicated to do this, as we need to calculate that from // the bottom -> top of the route but this information is valuable for profiling routes StringBuilder sb = new StringBuilder(); diff --git a/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedService.java b/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedService.java index 1eb11b7ebfb0b..b5dffe0d813fe 100644 --- a/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedService.java +++ b/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedService.java @@ -78,6 +78,10 @@ public String getCamelId() { return context.getName(); } + public String getCamelManagementName() { + return context.getManagementName(); + } + public String getRouteId() { if (route != null) { return route.getId(); diff --git a/camel-core/src/main/java/org/apache/camel/model/OptionalIdentifiedDefinition.java b/camel-core/src/main/java/org/apache/camel/model/OptionalIdentifiedDefinition.java index 33b00b918ddad..f48097b4038b0 100644 --- a/camel-core/src/main/java/org/apache/camel/model/OptionalIdentifiedDefinition.java +++ b/camel-core/src/main/java/org/apache/camel/model/OptionalIdentifiedDefinition.java @@ -20,7 +20,6 @@ import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlTransient; import javax.xml.bind.annotation.XmlType; import org.apache.camel.NamedNode; @@ -35,8 +34,7 @@ @XmlAccessorType(XmlAccessType.PROPERTY) public abstract class OptionalIdentifiedDefinition> implements NamedNode { private String id; - @XmlTransient - private boolean customId; + private Boolean customId; private DescriptionDefinition description; /** @@ -128,11 +126,20 @@ public String idOrCreate(NodeIdFactory factory) { return getId(); } + public Boolean isCustomId() { + return customId; + } + + @XmlAttribute + public void setCustomId(Boolean customId) { + this.customId = customId; + } + /** * Returns whether a custom id has been assigned */ public boolean hasCustomIdAssigned() { - return customId; + return customId != null && customId; } /** diff --git a/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java b/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java index 983ccbed96714..cb634c96986a0 100644 --- a/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java +++ b/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java @@ -101,6 +101,10 @@ public void testConstantExpression() throws Exception { assertExpression("Hello World", "Hello World"); } + public void testNull() throws Exception { + assertNull(SimpleLanguage.simple("${null}").evaluate(exchange, Object.class)); + } + public void testEmptyExpression() throws Exception { assertExpression("", ""); assertExpression(" ", " "); diff --git a/camel-core/src/test/java/org/apache/camel/model/GenerateXmFromCamelContextlTest.java b/camel-core/src/test/java/org/apache/camel/model/GenerateXmFromCamelContextTest.java similarity index 94% rename from camel-core/src/test/java/org/apache/camel/model/GenerateXmFromCamelContextlTest.java rename to camel-core/src/test/java/org/apache/camel/model/GenerateXmFromCamelContextTest.java index bd9223b3bcbe0..b711b109c04dd 100644 --- a/camel-core/src/test/java/org/apache/camel/model/GenerateXmFromCamelContextlTest.java +++ b/camel-core/src/test/java/org/apache/camel/model/GenerateXmFromCamelContextTest.java @@ -27,9 +27,9 @@ /** * @version */ -public class GenerateXmFromCamelContextlTest extends ContextTestSupport { +public class GenerateXmFromCamelContextTest extends ContextTestSupport { - public void testCreateRouteFromCamelCOntext() throws Exception { + public void testCreateRouteFromCamelContext() throws Exception { List list = context.getRouteDefinitions(); assertEquals("Size of list " + list, 1, list.size()); RouteDefinition routeType = list.get(0); diff --git a/camel-core/src/test/java/org/apache/camel/util/DumpModelAsXmlTransformRouteTest.java b/camel-core/src/test/java/org/apache/camel/util/DumpModelAsXmlTransformRouteTest.java index d32417121d71a..f63f7bb1cc99c 100644 --- a/camel-core/src/test/java/org/apache/camel/util/DumpModelAsXmlTransformRouteTest.java +++ b/camel-core/src/test/java/org/apache/camel/util/DumpModelAsXmlTransformRouteTest.java @@ -31,6 +31,7 @@ public void testDumpModelAsXml() throws Exception { log.info(xml); assertTrue(xml.contains("Hello ${body}")); + assertTrue(xml.contains("")); } @Override @@ -40,7 +41,7 @@ protected RouteBuilder createRouteBuilder() throws Exception { public void configure() throws Exception { from("direct:start").routeId("myRoute") .transform().simple("Hello ${body}") - .to("mock:result"); + .to("mock:result").id("myMock"); } }; } diff --git a/camel-core/src/test/java/org/apache/camel/util/jsse/SSLContextParametersTest.java b/camel-core/src/test/java/org/apache/camel/util/jsse/SSLContextParametersTest.java index 7351ac5b89772..11c82b20cc994 100644 --- a/camel-core/src/test/java/org/apache/camel/util/jsse/SSLContextParametersTest.java +++ b/camel-core/src/test/java/org/apache/camel/util/jsse/SSLContextParametersTest.java @@ -27,6 +27,8 @@ import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLSocket; +import junit.framework.AssertionFailedError; + import org.apache.camel.CamelContext; public class SSLContextParametersTest extends AbstractJsseParametersTest { @@ -40,6 +42,12 @@ public void testFilter() { Arrays.asList(new Pattern[0])); assertEquals(2, result.size()); assertStartsWith(result, "TLS"); + try { + assertStartsWith((String[]) null, "TLS"); + fail("We chould got an exception here!"); + } catch (AssertionFailedError ex) { + assertEquals("Get a wrong message", "The values should not be null", ex.getMessage()); + } } public void testPropertyPlaceholders() throws Exception { @@ -752,14 +760,16 @@ protected String[] getDefaultCipherSuiteIncludes(String[] availableCipherSuites) } protected void assertStartsWith(String[] values, String prefix) { + assertNotNull("The values should not be null", values); for (String value : values) { - assertTrue(value.startsWith(prefix)); + assertTrue(value + " does not start with the prefix " + prefix, value.startsWith(prefix)); } } protected void assertStartsWith(Collection values, String prefix) { + assertNotNull("The values should not be null", values); for (String value : values) { - assertTrue(value.startsWith(prefix)); + assertTrue(value + " does not start with the prefix " + prefix, value.startsWith(prefix)); } } } diff --git a/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiCamelContextNameStrategy.java b/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiCamelContextNameStrategy.java index 0f3fba92c0b77..a68c242980bad 100644 --- a/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiCamelContextNameStrategy.java +++ b/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiCamelContextNameStrategy.java @@ -16,15 +16,86 @@ */ package org.apache.camel.core.osgi; -import org.apache.camel.impl.DefaultCamelContextNameStrategy; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.camel.CamelContext; +import org.apache.camel.spi.CamelContextNameStrategy; import org.osgi.framework.BundleContext; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.ServiceReference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.apache.camel.core.osgi.OsgiCamelContextPublisher.CONTEXT_NAME_PROPERTY; + +/** + * In OSGi we want to use a {@link CamelContextNameStrategy} that finds a free name in the + * OSGi Service Registry to be used for auto assigned names. + *

+ * If there is a name clash in the OSGi registry, then a new candidate name is used by appending + * a unique counter. + */ +public class OsgiCamelContextNameStrategy implements CamelContextNameStrategy { -public class OsgiCamelContextNameStrategy extends DefaultCamelContextNameStrategy { + private static final Logger LOG = LoggerFactory.getLogger(OsgiCamelContextNameStrategy.class); + private static final AtomicInteger CONTEXT_COUNTER = new AtomicInteger(0); + private final BundleContext context; + private final String prefix = "camel"; + private volatile String name; public OsgiCamelContextNameStrategy(BundleContext context) { - // use bundle id in auto assigned names to make it unique and have the bundle id as prefix - // which makes the ordering of the camel apps in JMX nicely sorted - super(context.getBundle().getBundleId() + "-camel"); + this.context = context; + } + + @Override + public String getName() { + if (name == null) { + name = getNextName(); + } + return name; + } + + @Override + public synchronized String getNextName() { + String candidate = null; + boolean clash = false; + + do { + try { + clash = false; + + // generate new candidate + candidate = prefix + "-" + getNextCounter(); + LOG.trace("Checking OSGi Service Registry for existence of existing CamelContext with name: {}", candidate); + + ServiceReference[] refs = context.getServiceReferences(CamelContext.class.getName(), "(" + CONTEXT_NAME_PROPERTY + "=" + candidate + ")"); + if (refs != null && refs.length > 0) { + for (ServiceReference ref : refs) { + Object id = ref.getProperty(CONTEXT_NAME_PROPERTY); + if (id != null && candidate.equals(id)) { + clash = true; + break; + } + } + } + } catch (InvalidSyntaxException e) { + LOG.debug("Error finding free Camel name in OSGi Service Registry due " + e.getMessage() + ". This exception is ignored.", e); + break; + } + } while (clash); + + LOG.debug("Generated CamelContext name for bundle id: {}, clash: {} -> {}", new Object[]{context.getBundle().getBundleId(), clash, candidate}); + return candidate; + } + + @Override + public boolean isFixedName() { + return false; + } + + public static int getNextCounter() { + // we want to start counting from 1, so increment first + return CONTEXT_COUNTER.incrementAndGet(); } } diff --git a/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiManagementNameStrategy.java b/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiManagementNameStrategy.java index 9b6a151076504..f870ca20fe520 100644 --- a/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiManagementNameStrategy.java +++ b/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiManagementNameStrategy.java @@ -23,7 +23,7 @@ import org.osgi.framework.BundleContext; /** - * OSGI enhanced {@link org.apache.camel.spi.ManagementNameStrategy}. + * OSGi enhanced {@link org.apache.camel.spi.ManagementNameStrategy}. *

* This {@link org.apache.camel.spi.ManagementNameStrategy} supports the default * tokens (see {@link DefaultManagementNameStrategy}) and the following additional OSGi specific tokens @@ -33,8 +33,9 @@ *

  • #symbolicName# - The bundle symbolic name
  • * *

    - * This implementation will by default use a name pattern as #bundleId#-#name# and in case - * of a clash, then the pattern will fallback to be using the counter as #bundleId#-#name#-#counter#. + * This implementation will by default use a name pattern as #symbolicName# and in case + * of a clash (such as multiple versions of the same symbolicName), + * then the pattern will fallback to append an unique counter #symbolicName#-#counter#. * * @see DefaultManagementNameStrategy */ @@ -43,7 +44,7 @@ public class OsgiManagementNameStrategy extends DefaultManagementNameStrategy { private final BundleContext bundleContext; public OsgiManagementNameStrategy(CamelContext camelContext, BundleContext bundleContext) { - super(camelContext, "#bundleId#-#name#", "#bundleId#-#name#-#counter#"); + super(camelContext, "#symbolicName#", "#symbolicName#-#counter#"); this.bundleContext = bundleContext; } diff --git a/components/camel-cxf-transport/src/main/java/org/apache/camel/component/cxf/common/header/CxfHeaderHelper.java b/components/camel-cxf-transport/src/main/java/org/apache/camel/component/cxf/common/header/CxfHeaderHelper.java index 7e1672db7a5da..e7a215421fcc5 100644 --- a/components/camel-cxf-transport/src/main/java/org/apache/camel/component/cxf/common/header/CxfHeaderHelper.java +++ b/components/camel-cxf-transport/src/main/java/org/apache/camel/component/cxf/common/header/CxfHeaderHelper.java @@ -68,9 +68,10 @@ public static void propagateCamelToCxf(HeaderFilterStrategy strategy, if (Exchange.CONTENT_TYPE.equals(entry.getKey())) { message.put(Message.CONTENT_TYPE, entry.getValue()); - } else if (Client.REQUEST_CONTEXT.equals(entry.getKey()) - || Client.RESPONSE_CONTEXT.equals(entry.getKey()) - || Message.RESPONSE_CODE.equals(entry.getKey())) { + } + if (Client.REQUEST_CONTEXT.equals(entry.getKey()) + || Client.RESPONSE_CONTEXT.equals(entry.getKey()) + || Message.RESPONSE_CODE.equals(entry.getKey())) { message.put(entry.getKey(), entry.getValue()); } else { Object values = entry.getValue(); diff --git a/components/camel-cxf-transport/src/test/java/org/apache/camel/component/cxf/common/header/CxfHeaderHelperTest.java b/components/camel-cxf-transport/src/test/java/org/apache/camel/component/cxf/common/header/CxfHeaderHelperTest.java index 25fd240dfb71b..9698f263661da 100755 --- a/components/camel-cxf-transport/src/test/java/org/apache/camel/component/cxf/common/header/CxfHeaderHelperTest.java +++ b/components/camel-cxf-transport/src/test/java/org/apache/camel/component/cxf/common/header/CxfHeaderHelperTest.java @@ -17,6 +17,7 @@ package org.apache.camel.component.cxf.common.header; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.TreeMap; @@ -26,11 +27,15 @@ import org.apache.camel.impl.DefaultCamelContext; import org.apache.camel.impl.DefaultExchange; import org.apache.camel.impl.DefaultHeaderFilterStrategy; - +import org.apache.camel.spi.HeaderFilterStrategy; import org.apache.cxf.helpers.CastUtils; +import org.apache.cxf.message.Message; +import org.apache.cxf.message.MessageImpl; +import org.easymock.EasyMock; import org.junit.Assert; import org.junit.Test; + /** * */ @@ -104,7 +109,24 @@ public void testPropagateCxfToCamelWithMerged() { assertEquals("peach", camelHeaders.get("MyFruitHeader")); assertEquals("cappuccino, espresso", camelHeaders.get("MyBrewHeader")); } - + + @Test + public void testContentType() { + + Exchange camelExchange = EasyMock.createMock(Exchange.class); + HeaderFilterStrategy strategy = setupHeaderStrategy(camelExchange); + Message cxfMessage = new MessageImpl(); + CxfHeaderHelper.propagateCamelToCxf(strategy, + Collections.singletonMap("Content-Type", "text/xml"), cxfMessage, camelExchange); + + Map> cxfHeaders = CastUtils.cast((Map)cxfMessage.get(Message.PROTOCOL_HEADERS)); + assertEquals(1, cxfHeaders.size()); + assertEquals(1, cxfHeaders.get("Content-Type").size()); + assertEquals("text/xml", cxfHeaders.get("Content-Type").get(0)); + + assertEquals("text/xml", cxfMessage.get(Message.CONTENT_TYPE)); + } + private void verifyHeader(Map> headers, String name, List value) { List values = headers.get(name); assertTrue("The entry must be available", values != null && values.size() == ((List)value).size()); @@ -116,4 +138,14 @@ private void verifyHeader(Map> headers, String name, String assertTrue("The entry must be available", values != null && values.size() == 1); assertEquals("The value must match", value, values.get(0)); } + + private HeaderFilterStrategy setupHeaderStrategy(Exchange exchange) { + + HeaderFilterStrategy strategy = EasyMock.createMock(HeaderFilterStrategy.class); + strategy.applyFilterToCamelHeaders("Content-Type", "text/xml", exchange); + EasyMock.expectLastCall().andReturn(false); + EasyMock.replay(strategy); + return strategy; + } + } diff --git a/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/jaxrs/CxfRsEndpoint.java b/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/jaxrs/CxfRsEndpoint.java index 1e1296b944db9..0b4c816866201 100644 --- a/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/jaxrs/CxfRsEndpoint.java +++ b/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/jaxrs/CxfRsEndpoint.java @@ -408,6 +408,10 @@ public void setSchemaLocation(String schema) { public void setSchemaLocations(List schemas) { this.schemaLocations = schemas; } + + public List getSchemaLocations() { + return schemaLocations; + } /** * See documentation of {@link BindingStyle}. diff --git a/components/camel-disruptor/src/main/java/org/apache/camel/component/disruptor/DisruptorEndpoint.java b/components/camel-disruptor/src/main/java/org/apache/camel/component/disruptor/DisruptorEndpoint.java index 9ed263ca75107..9ad8cfbd55f87 100644 --- a/components/camel-disruptor/src/main/java/org/apache/camel/component/disruptor/DisruptorEndpoint.java +++ b/components/camel-disruptor/src/main/java/org/apache/camel/component/disruptor/DisruptorEndpoint.java @@ -14,7 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.apache.camel.component.disruptor; import java.util.Collection; @@ -32,8 +31,10 @@ import org.apache.camel.MultipleConsumersSupport; import org.apache.camel.Processor; import org.apache.camel.Producer; +import org.apache.camel.ServiceStatus; import org.apache.camel.WaitForTaskToComplete; import org.apache.camel.api.management.ManagedAttribute; +import org.apache.camel.api.management.ManagedResource; import org.apache.camel.impl.DefaultEndpoint; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,20 +44,16 @@ * for asynchronous SEDA exchanges on an * LMAX Disruptor within a CamelContext */ - +@ManagedResource(description = "Managed Disruptor Endpoint") public class DisruptorEndpoint extends DefaultEndpoint implements MultipleConsumersSupport { public static final String DISRUPTOR_IGNORE_EXCHANGE = "disruptor.ignoreExchange"; private static final Logger LOGGER = LoggerFactory.getLogger(DisruptorEndpoint.class); - private final int concurrentConsumers; private final boolean multipleConsumers; private WaitForTaskToComplete waitForTaskToComplete = WaitForTaskToComplete.IfReplyExpected; - private long timeout = 30000; - private boolean blockWhenFull; - private final Set producers = new CopyOnWriteArraySet(); private final Set consumers = new CopyOnWriteArraySet(); @@ -72,6 +69,31 @@ public DisruptorEndpoint(final String endpointUri, final Component component, this.blockWhenFull = blockWhenFull; } + @ManagedAttribute(description = "Camel ID") + public String getCamelId() { + return getCamelContext().getName(); + } + + @ManagedAttribute(description = "Camel ManagementName") + public String getCamelManagementName() { + return getCamelContext().getManagementName(); + } + + @ManagedAttribute(description = "Endpoint Uri", mask = true) + public String getEndpointUri() { + return super.getEndpointUri(); + } + + @ManagedAttribute(description = "Service State") + public String getState() { + ServiceStatus status = this.getStatus(); + // if no status exists then its stopped + if (status == null) { + status = ServiceStatus.Stopped; + } + return status.name(); + } + @ManagedAttribute(description = "Buffer max capacity") public int getBufferSize() { return disruptorReference.getBufferSize(); @@ -87,7 +109,6 @@ public long getPendingExchangeCount() throws DisruptorNotStartedException { return getDisruptor().getPendingExchangeCount(); } - @ManagedAttribute(description = "Number of concurrent consumers") public int getConcurrentConsumers() { return concurrentConsumers; @@ -165,23 +186,18 @@ public Consumer createConsumer(final Processor processor) throws Exception { @Override protected void doStart() throws Exception { - LOGGER.debug("Start enpoint {}", this); // notify reference we are shutting down this endpoint disruptorReference.addEndpoint(this); - - super.doStart(); //To change body of overridden methods use File | Settings | File Templates. + super.doStart(); } @Override protected void doStop() throws Exception { - LOGGER.debug("Stop enpoint {}", this); // notify reference we are shutting down this endpoint disruptorReference.removeEndpoint(this); - - super.doStop(); //To change body of overridden methods use File | Settings | File Templates. + super.doStop(); } - @Override protected void doShutdown() throws Exception { // notify component we are shutting down this endpoint @@ -204,35 +220,24 @@ void onStarted(final DisruptorConsumer consumer) throws Exception { throw new IllegalStateException( "Multiple consumers for the same endpoint is not allowed: " + this); } - if (consumers.add(consumer)) { LOGGER.debug("Starting consumer {} on endpoint {}", consumer, getEndpointUri()); - getDisruptor().reconfigure(); - } else { - LOGGER.debug("Tried to start Consumer {} on endpoint {} but it was already started", consumer, - getEndpointUri()); + LOGGER.debug("Tried to start Consumer {} on endpoint {} but it was already started", consumer, getEndpointUri()); } } - } void onStopped(final DisruptorConsumer consumer) throws Exception { synchronized (this) { - if (consumers.remove(consumer)) { LOGGER.debug("Stopping consumer {} on endpoint {}", consumer, getEndpointUri()); - getDisruptor().reconfigure(); - } else { - LOGGER.debug("Tried to stop Consumer {} on endpoint {} but it was already stopped", consumer, - getEndpointUri()); + LOGGER.debug("Tried to stop Consumer {} on endpoint {} but it was already stopped", consumer, getEndpointUri()); } - - } } diff --git a/components/camel-gora/pom.xml b/components/camel-gora/pom.xml new file mode 100644 index 0000000000000..d808643808948 --- /dev/null +++ b/components/camel-gora/pom.xml @@ -0,0 +1,178 @@ + + + + 4.0.0 + + + org.apache.camel + components + 2.13-SNAPSHOT + + + camel-gora + bundle + Camel :: Gora + + + Gora Component for Apache Camel. + + + + + org.apache.camel.component.gora.* + + + org.apache.camel.* + com.google.common.base;version="[11,14)", + org.apache.hadoop.conf;version="[1,2)" + + org.apache.camel.component.gora.* + org.apache.camel.spi.ComponentResolver;component=gora + + + + + + + maven-surefire-plugin + + + + warn + + + + + + + + + + + + org.slf4j + slf4j-simple + test + + + + + junit + junit + test + + + org.mockito + mockito-all + ${mockito-version} + test + + + org.powermock + powermock-core + ${powermock-version} + test + + + org.powermock + powermock-module-junit4 + ${powermock-version} + test + + + org.powermock + powermock-api-mockito + ${powermock-version} + test + + + org.apache.camel + camel-test + test + + + org.apache.camel + camel-test-spring + test + + + + + org.apache.camel + camel-core + + + + + org.apache.gora + gora-core + ${apache-gora-version} + + + + + org.apache.servicemix.bundles + org.apache.servicemix.bundles.hadoop-core + ${hadoop-bundle-version} + + + commons-beanutils + commons-beanutils-core + + + + + + + org.apache.servicemix.bundles + org.apache.servicemix.bundles.avro + ${avro-bundle-version} + + + + + + org.codehaus.jackson + jackson-core-asl + ${jackson-version} + + + org.codehaus.jackson + jackson-mapper-asl + ${jackson-version} + + + org.apache.servicemix.bundles + org.apache.servicemix.bundles.jdom + ${jdom-bundle-version} + + + com.google.guava + guava + ${google-guava-version} + + + org.apache.servicemix.bundles + org.apache.servicemix.bundles.commons-beanutils + ${commons-beanutils-bundle-version} + + + + diff --git a/components/camel-gora/src/main/java/org/apache/camel/component/gora/GoraAttribute.java b/components/camel-gora/src/main/java/org/apache/camel/component/gora/GoraAttribute.java new file mode 100644 index 0000000000000..aeab95f469d13 --- /dev/null +++ b/components/camel-gora/src/main/java/org/apache/camel/component/gora/GoraAttribute.java @@ -0,0 +1,106 @@ +/** + * 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.component.gora; + +/** + * Camel-Gora attributes + * + * @author ipolyzos + */ +public enum GoraAttribute { + + /** + * Gora KEY attribute + */ + GORA_KEY("goraKey"), + + /** + * Gora operation header name + */ + GORA_OPERATION("goraOperation"), + + /** + * Gora Query Start Time attribute + */ + GORA_QUERY_START_TIME("startTime"), + + /** + * Gora Query End Time attribute + */ + GORA_QUERY_END_TIME("endTime"), + + /** + * Gora Query Start Key attribute + */ + GORA_QUERY_START_KEY("startKey"), + + /** + * Gora Query End Key attribute + */ + GORA_QUERY_END_KEY("endKey"), + + /** + * Gora Query Key Range From attribute + */ + GORA_QUERY_KEY_RANGE_FROM("keyRangeFrom"), + + /** + * Gora Query Key Range To attribute + */ + GORA_QUERY_KEY_RANGE_TO("keyRangeTo"), + + /** + * Gora Query Time Range From attribute + */ + GORA_QUERY_TIME_RANGE_FROM("timeRangeFrom"), + + /** + * Gora Query Key Range To attribute + */ + GORA_QUERY_TIME_RANGE_TO("timeRangeTo"), + + /** + * Gora Query Limit attribute + */ + GORA_QUERY_LIMIT("limit"), + + /** + * Gora Query Timestamp attribute + */ + GORA_QUERY_TIMESTAMP("timestamp"), + + /** + * Gora Query Fields attribute + */ + GORA_QUERY_FIELDS("fields"); + /** + * Enum value + */ + public final String value; + + /** + * Enum constructor + * + * @param str Operation Value + */ + private GoraAttribute(final String str) { + + value = str; + } + +} diff --git a/components/camel-gora/src/main/java/org/apache/camel/component/gora/GoraComponent.java b/components/camel-gora/src/main/java/org/apache/camel/component/gora/GoraComponent.java new file mode 100644 index 0000000000000..546b9dc06ac5d --- /dev/null +++ b/components/camel-gora/src/main/java/org/apache/camel/component/gora/GoraComponent.java @@ -0,0 +1,122 @@ +/** + * 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.component.gora; + +import org.apache.camel.Endpoint; +import org.apache.camel.impl.DefaultComponent; +import org.apache.gora.persistency.Persistent; +import org.apache.gora.store.DataStore; +import org.apache.gora.store.DataStoreFactory; +import org.apache.hadoop.conf.Configuration; + +import java.io.IOException; +import java.util.Map; +import java.util.Properties; + +import static org.apache.camel.component.gora.GoraConstants.GORA_DEFAULT_DATASTORE_KEY; + +/** + * Camel-Gora {@link Endpoint}. + */ +public class GoraComponent extends DefaultComponent { + + /** + * GORA datastore + */ + private DataStore dataStore; + /** + * GORA properties + */ + private Properties goraProperties; + /** + * Hadoop configuration + */ + private Configuration configuration; + + /** + * Initialize class and create DataStore instance + * + * @param config component configuration + * @throws IOException + */ + private void init(final GoraConfiguration config) throws IOException { + + this.goraProperties = DataStoreFactory.createProps(); + + this.dataStore = DataStoreFactory.getDataStore(goraProperties.getProperty(GORA_DEFAULT_DATASTORE_KEY, + config.getDataStoreClass()), + config.getKeyClass(), + config.getValueClass(), + this.configuration); + } + + /** + * {@inheritDoc} + */ + @Override + protected void doStart() throws Exception { + + if (configuration == null) { + configuration = new Configuration(); + } + } + + /** + * {@inheritDoc} + */ + @Override + protected void doStop() throws Exception { + + if (dataStore != null) { + dataStore.close(); + } + } + + /** + * {@inheritDoc} + */ + @Override + protected Endpoint createEndpoint(final String uri, + final String remaining, + final Map parameters) throws Exception { + + final GoraConfiguration config = new GoraConfiguration(); + setProperties(config, parameters); + + try { + + init(config); + } catch (IOException ex) { + + throw new RuntimeException(ex); + } + + return new GoraEndpoint(uri, this, config, dataStore); + } + + /** + * Get DataStore + * + * @return DataStore + */ + public DataStore getDataStore() { + + return dataStore; + } + +} \ No newline at end of file diff --git a/components/camel-gora/src/main/java/org/apache/camel/component/gora/GoraConfiguration.java b/components/camel-gora/src/main/java/org/apache/camel/component/gora/GoraConfiguration.java new file mode 100644 index 0000000000000..5456522132add --- /dev/null +++ b/components/camel-gora/src/main/java/org/apache/camel/component/gora/GoraConfiguration.java @@ -0,0 +1,472 @@ +/** + * 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.component.gora; + +import com.google.common.base.Strings; +import org.apache.hadoop.conf.Configuration; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Strings.isNullOrEmpty; + + +/** + * Gora Configuration. + * + */ +public class GoraConfiguration { + + /** + * key type + */ + private String keyClass; + + /** + * configuration + */ + private Configuration hadoopConfiguration; + + /** + * value type + */ + private String valueClass; + + /** + * dataStore type + */ + private String dataStoreClass; + + /** Consumer only properties! */ + + /** + * Gora Query Start Time attribute + */ + private long startTime; + + /** + * Gora Query End Time attribute + */ + private long endTime; + + /** + * Gora Query Time Range From attribute + */ + private long timeRangeFrom; + + /** + * Gora Query Key Range To attribute + */ + private long timeRangeTo; + + /** + * Gora Query Limit attribute + */ + private long limit; + + /** + * Gora Query Timestamp attribute + */ + private long timestamp; + + /** + * Gora Query Start Key attribute + */ + private Object startKey; + + /** + * Gora Query End Key attribute + */ + private Object endKey; + + /** + * Gora Query Key Range From attribute + */ + private Object keyRangeFrom; + + /** + * Gora Query Key Range To attribute + */ + private Object keyRangeTo; + + + /** + * Gora Query Fields attribute + */ + private Strings fields; + + /** + * Concurrent Consumers + * + * NOTE: used only by consumer + */ + private int concurrentConsumers = 1; + + /** + * Flush on every operation + * + * NOTE: used only by producer + */ + private boolean flushOnEveryOperation = true; + + /** + * Default Constructor + */ + public GoraConfiguration() { + + this.hadoopConfiguration = new Configuration(); + } + + /** + * Get type of the key (i.e clients) + * + * @return key class + */ + public String getKeyClass() { + + return keyClass; + } + + /** + * Set type class of the key + * + * @param keyClass + */ + public void setKeyClass(final String keyClass) { + + if (isNullOrEmpty(keyClass)) { + throw new IllegalArgumentException("Key class could not be null or empty!"); + } + + this.keyClass = keyClass; + } + + /** + * Get type of the value + * + * @return + */ + public String getValueClass() { + + return valueClass; + } + + /** + * Set type of the value + * + * @param valueClass + */ + public void setValueClass(final String valueClass) { + + if (isNullOrEmpty(valueClass)) { + throw new IllegalArgumentException("Value class could not be null or empty!"); + } + + this.valueClass = valueClass; + } + + /** + * Get type of the dataStore + * + * @return DataStore class + */ + public String getDataStoreClass() { + + return dataStoreClass; + } + + /** + * Set type of the dataStore + * + * @param dataStoreClass + */ + public void setDataStoreClass(String dataStoreClass) { + + + if (isNullOrEmpty(dataStoreClass)) { + throw new IllegalArgumentException("DataStore class could not be null or empty!"); + } + + this.dataStoreClass = dataStoreClass; + } + + /** + * Get Hadoop Configuration + * + * @return + */ + public Configuration getHadoopConfiguration() { + + return hadoopConfiguration; + } + + /** + * Get Start Time + * + * @return + */ + public long getStartTime() { + + return startTime; + } + + /** + * Set Start Time + * + * @return + */ + public void setStartTime(long startTime) { + + this.startTime = startTime; + } + + /** + * Get End Time + * + * @return + */ + public long getEndTime() { + + return endTime; + } + + /** + * Set End Time + * + * @return + */ + public void setEndTime(long endTime) { + + this.endTime = endTime; + } + + /** + * Get Time Range From + * + * @return + */ + public long getTimeRangeFrom() { + + return timeRangeFrom; + } + + /** + * Set Time Range From + * + * @return + */ + public void setTimeRangeFrom(long timeRangeFrom) { + + this.timeRangeFrom = timeRangeFrom; + } + + /** + * Get Time Range To + * + * @return + */ + public long getTimeRangeTo() { + + return timeRangeTo; + } + + /** + * Set Time Range To + * + * @return + */ + public void setTimeRangeTo(long timeRangeTo) { + + this.timeRangeTo = timeRangeTo; + } + + /** + * Get Limit + * + * @return + */ + public long getLimit() { + + return limit; + } + + /** + * Set Limit + * + * @param limit + */ + public void setLimit(long limit) { + this.limit = limit; + } + + /** + * Get Timestamp + * + * @return + */ + public long getTimestamp() { + + return timestamp; + } + + /** + * Set Timestamp + * + * @param timestamp + */ + public void setTimestamp(long timestamp) { + + this.timestamp = timestamp; + } + + /** + * Get Start Key + * + * @return + */ + public Object getStartKey() { + return startKey; + } + + /** + * Set Start Key + * + * @param startKey + */ + public void setStartKey(Object startKey) { + this.startKey = startKey; + } + + /** + * Get End Key + * + * @return + */ + public Object getEndKey() { + return endKey; + } + + /** + * Set End Key + * + * @param endKey + */ + public void setEndKey(Object endKey) { + this.endKey = endKey; + } + + /** + * Get Key Range From + * @return + */ + public Object getKeyRangeFrom() { + return keyRangeFrom; + } + + /** + * Set Key Range From + * + * @param keyRangeFrom + */ + public void setKeyRangeFrom(Object keyRangeFrom) { + this.keyRangeFrom = keyRangeFrom; + } + + /** + * Get Key Range To + * @return + */ + public Object getKeyRangeTo() { + return keyRangeTo; + } + + /** + * Set Key Range To + * + * @param keyRangeTo + */ + public void setKeyRangeTo(Object keyRangeTo) { + this.keyRangeTo = keyRangeTo; + } + + /** + * Get Fields + * + * @return + */ + public Strings getFields() { + + return fields; + } + + /** + * Set Fields + * + * @param fields + */ + public void setFields(Strings fields) { + + this.fields = fields; + } + + /** + * Get Concurrent Consumers + * @return + */ + public int getConcurrentConsumers() { + + return concurrentConsumers; + } + + /** + * Set Concurrent Consumers + * + * @param concurrentConsumers + */ + public void setConcurrentConsumers(int concurrentConsumers) { + + this.concurrentConsumers = concurrentConsumers; + } + + /** + * Get flush on every operation + * + * @return + */ + public boolean isFlushOnEveryOperation() { + return flushOnEveryOperation; + } + + /** + * Set flush on every operation + * + * @param flushOnEveryOperation + */ + public void setFlushOnEveryOperation(boolean flushOnEveryOperation) { + this.flushOnEveryOperation = flushOnEveryOperation; + } + + /** + * Set Hadoop Configuration + * + * @param hadoopConfiguration + */ + public void setHadoopConfiguration(Configuration hadoopConfiguration) { + + checkNotNull(hadoopConfiguration, "Hadoop Configuration could not be null!"); + this.hadoopConfiguration = hadoopConfiguration; + } +} diff --git a/components/camel-gora/src/main/java/org/apache/camel/component/gora/GoraConstants.java b/components/camel-gora/src/main/java/org/apache/camel/component/gora/GoraConstants.java new file mode 100644 index 0000000000000..de08fb7fed66a --- /dev/null +++ b/components/camel-gora/src/main/java/org/apache/camel/component/gora/GoraConstants.java @@ -0,0 +1,39 @@ +/** + * 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.component.gora; + +/** + * Camel Gora component constants + * + * @author ipolyzos + */ +public final class GoraConstants { + + /** + * default DataStore key + */ + public static final String GORA_DEFAULT_DATASTORE_KEY = "gora.datastore.default"; + + /** + * Private constructor + */ + private GoraConstants() { + // prevent instantiation + } + +} diff --git a/components/camel-gora/src/main/java/org/apache/camel/component/gora/GoraConsumer.java b/components/camel-gora/src/main/java/org/apache/camel/component/gora/GoraConsumer.java new file mode 100644 index 0000000000000..24c2e227db4d2 --- /dev/null +++ b/components/camel-gora/src/main/java/org/apache/camel/component/gora/GoraConsumer.java @@ -0,0 +1,128 @@ +/** + * 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.component.gora; + +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.ExecutorService; + +import org.apache.camel.Consumer; +import org.apache.camel.Endpoint; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.camel.component.gora.utils.GoraUtils; +import org.apache.camel.impl.ScheduledPollConsumer; +import org.apache.gora.persistency.Persistent; +import org.apache.gora.query.Query; +import org.apache.gora.query.Result; +import org.apache.gora.store.DataStore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Implementation of Camel-Gora {@link Consumer}. + * + */ +public class GoraConsumer extends ScheduledPollConsumer { + + /** + * logger + */ + private static final Logger LOG = LoggerFactory.getLogger(GoraConsumer.class); + + /** + * GORA datastore + */ + private final DataStore dataStore; + + /** + * Camel-Gora endpoint configuration + */ + private final GoraConfiguration configuration; + + /** + * Camel Gora Query + */ + private Query query; + + /** + * executor service + */ + private ExecutorService executor; + + /** + * Poll run + */ + private boolean firstRun; + + + /** + * Consumer Constructor + * + * @param endpoint Reference to the Camel-Gora endpoint + * @param processor Reference to Consumer Processor + * @param configuration Reference to Camel-Gora endpoint configuration + * @param dataStore Reference to the datastore + */ + public GoraConsumer(final Endpoint endpoint, + final Processor processor, + final GoraConfiguration configuration, + final DataStore dataStore) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { + + super(endpoint, processor); + + this.configuration = configuration; + this.dataStore = dataStore; + + this.query = GoraUtils.constractQueryFromConfiguration(this.dataStore, this.configuration); + } + + /** + * {@inheritDoc} + */ + @Override + protected int poll() throws Exception { + + final Exchange exchange = this.getEndpoint().createExchange(); + + // compute time (aprox) since last update + if (firstRun) { + this.query.setStartTime(System.currentTimeMillis()); + } else { + this.query.setStartTime(System.currentTimeMillis() - getDelay()); + } + + //proceed with query + final Result result = query.execute(); + + LOG.trace("Processing exchange [{}]...", exchange); + + try { + + getProcessor().process(exchange); + } finally { + + if (exchange.getException() != null) { + + getExceptionHandler().handleException("Error processing exchange", exchange, exchange.getException()); + } + } + + return Long.valueOf(result.getOffset()).intValue(); + } +} + diff --git a/components/camel-gora/src/main/java/org/apache/camel/component/gora/GoraEndpoint.java b/components/camel-gora/src/main/java/org/apache/camel/component/gora/GoraEndpoint.java new file mode 100644 index 0000000000000..df5c62813f8af --- /dev/null +++ b/components/camel-gora/src/main/java/org/apache/camel/component/gora/GoraEndpoint.java @@ -0,0 +1,105 @@ +/** + * 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.component.gora; + +import org.apache.camel.Consumer; +import org.apache.camel.Processor; +import org.apache.camel.Producer; +import org.apache.camel.impl.DefaultEndpoint; +import org.apache.gora.persistency.Persistent; +import org.apache.gora.store.DataStore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Gora endpoint + * + * @author ipolyzos + */ +public class GoraEndpoint extends DefaultEndpoint { + + /** + * logger + */ + private static final Logger LOG = LoggerFactory.getLogger(GoraEndpoint.class); + + /** + * Gora DataStore + */ + private final DataStore dataStore; + + /** + * Camel-Gora Endpoint Configuratopn + */ + private GoraConfiguration configuration; + + /** + * GORA endpoint default constructor + * + * @param uri Endpoint URI + * @param goraComponent Reference to the Camel-Gora component + * @param config Reference to Camel-Gora endpoint configuration + * @param dataStore Reference to Gora DataStore + */ + public GoraEndpoint(final String uri, + final GoraComponent goraComponent, + final GoraConfiguration config, + final DataStore dataStore) { + + super(uri, goraComponent); + this.configuration = config; + this.dataStore = dataStore; + } + + /** + * {@inheritDoc} + */ + @Override + public Producer createProducer() throws Exception { + + return new GoraProducer(this, this.configuration, this.dataStore); + } + + /** + * {@inheritDoc} + */ + @Override + public Consumer createConsumer(final Processor processor) throws Exception { + + return new GoraConsumer(this, processor, this.configuration, this.dataStore); + } + + /** + * Get Configutation + * + * @return + */ + public GoraConfiguration getConfiguration() { + return configuration; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isSingleton() { + + return true; + } + +} diff --git a/components/camel-gora/src/main/java/org/apache/camel/component/gora/GoraOperation.java b/components/camel-gora/src/main/java/org/apache/camel/component/gora/GoraOperation.java new file mode 100644 index 0000000000000..3fd428409194a --- /dev/null +++ b/components/camel-gora/src/main/java/org/apache/camel/component/gora/GoraOperation.java @@ -0,0 +1,85 @@ +/** + * 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.component.gora; + +/** + * Camel-Gora Operations. + * + * @author ipolyzos + */ +public enum GoraOperation { + + /** + * Gora "put" operation + */ + PUT("put"), + + /** + * Gora fetch/"get" operation + */ + GET("get"), + + /** + * Gora "delete" operation + */ + DELETE("delete"), + + /** + * Gora "get schema name" operation + */ + GET_SCHEMA_NAME("getSchemaName"), + + /** + * Gora "delete schema" operation + */ + DELETE_SCHEMA("deleteSchema"), + + /** + * Gora "create schema" operation + */ + CREATE_SCHEMA("createSchema"), + + /** + * Gora "query" operation + */ + QUERY("query"), + + /** + * Gora "deleteByQuery" operation + */ + DELETE_BY_QUERY("deleteByQuery"), + + /** + * Gora "schemaExists" operation + */ + SCHEMA_EXIST("schemaExists"); + + /** + * Enum value + */ + public final String value; + + /** + * Enum constructor + * + * @param str Operation Value + */ + private GoraOperation(final String str) { + + value = str; + } +} diff --git a/components/camel-gora/src/main/java/org/apache/camel/component/gora/GoraProducer.java b/components/camel-gora/src/main/java/org/apache/camel/component/gora/GoraProducer.java new file mode 100644 index 0000000000000..7e25fd5e03c08 --- /dev/null +++ b/components/camel-gora/src/main/java/org/apache/camel/component/gora/GoraProducer.java @@ -0,0 +1,134 @@ +/** + * 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.component.gora; + +import java.util.Map; + +import org.apache.camel.Endpoint; +import org.apache.camel.Exchange; +import org.apache.camel.ServicePoolAware; +import org.apache.camel.impl.DefaultProducer; +import org.apache.gora.persistency.Persistent; +import org.apache.gora.store.DataStore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.apache.camel.component.gora.utils.GoraUtils.constractQueryFromPropertiesMap; +import static org.apache.camel.component.gora.utils.GoraUtils.getKeyFromExchange; +import static org.apache.camel.component.gora.utils.GoraUtils.getValueFromExchange; + + +/** + * Camel-Gora {@link DefaultProducer}. + * + */ +public class GoraProducer extends DefaultProducer implements ServicePoolAware { + + /** + * logger + */ + private static final Logger LOG = LoggerFactory.getLogger(GoraProducer.class); + + /** + * Camel-Gora endpoint configuration + */ + private final GoraConfiguration configuration; + + /** + * GORA datastore + */ + private final DataStore dataStore; + + /** + * Constructor + * + * @param endpoint Reference to the Camel-Gora endpoint + * @param configuration Reference to Camel-Gora endpoint configuration + * @param dataStore Reference to the datastore + */ + public GoraProducer(final Endpoint endpoint, + final GoraConfiguration configuration, + final DataStore dataStore) { + + super(endpoint); + this.dataStore = dataStore; + this.configuration = configuration; + } + + /** + * {@inheritDoc} + */ + @Override + public void process(final Exchange exchange) throws Exception { + + final String operation = (String) exchange.getIn().getHeader(GoraAttribute.GORA_OPERATION.value); + + if (operation == null || operation.isEmpty()) { + + throw new RuntimeException("Gora operation is null or empty!"); + } + + Object result = 0; // 0 used as default response in order to avoid null body exception + + if (GoraOperation.PUT.value.equalsIgnoreCase(operation)) { + + dataStore.put(getKeyFromExchange(exchange), getValueFromExchange(exchange)); + } else if (GoraOperation.GET.value.equalsIgnoreCase(operation)) { + + result = dataStore.get(getKeyFromExchange(exchange)); + } else if (GoraOperation.DELETE.value.equalsIgnoreCase(operation)) { + + result = dataStore.delete(getKeyFromExchange(exchange)); + } else if (GoraOperation.QUERY.value.equalsIgnoreCase(operation)) { + + final Map props = exchange.getIn().getHeaders(); + result = constractQueryFromPropertiesMap(props, dataStore, this.configuration).execute(); + } else if (GoraOperation.DELETE_BY_QUERY.value.equalsIgnoreCase(operation)) { + + final Map props = exchange.getIn().getHeaders(); + result = dataStore.deleteByQuery(constractQueryFromPropertiesMap(props, dataStore, this.configuration)); + } else if (GoraOperation.GET_SCHEMA_NAME.value.equalsIgnoreCase(operation)) { + + result = dataStore.getSchemaName(); + } else if (GoraOperation.DELETE_SCHEMA.value.equalsIgnoreCase(operation)) { + + dataStore.deleteSchema(); + } else if (GoraOperation.CREATE_SCHEMA.value.equalsIgnoreCase(operation)) { + + dataStore.createSchema(); + } else if (GoraOperation.SCHEMA_EXIST.value.equalsIgnoreCase(operation)) { + + result = dataStore.schemaExists(); + } else { + + throw new RuntimeException("Unknown operation!"); + } + + /* + from the tests auto-flush seems not to work always + therefore a temporary solution is calling flush + on every action + */ + if (configuration.isFlushOnEveryOperation()) { + dataStore.flush(); + } + + exchange.getOut().setBody(result); + } + +} diff --git a/components/camel-gora/src/main/java/org/apache/camel/component/gora/utils/GoraUtils.java b/components/camel-gora/src/main/java/org/apache/camel/component/gora/utils/GoraUtils.java new file mode 100644 index 0000000000000..58c4cf66715d7 --- /dev/null +++ b/components/camel-gora/src/main/java/org/apache/camel/component/gora/utils/GoraUtils.java @@ -0,0 +1,318 @@ +/** + * 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.component.gora.utils; + +import java.lang.reflect.InvocationTargetException; +import java.util.Map; + +import org.apache.camel.Exchange; +import org.apache.camel.component.gora.GoraAttribute; +import org.apache.camel.component.gora.GoraConfiguration; +import org.apache.commons.beanutils.PropertyUtils; +import org.apache.gora.persistency.Persistent; +import org.apache.gora.query.Query; +import org.apache.gora.store.DataStore; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * GoraUtil class contain utility methods for the + * camel component. + * + */ +public final class GoraUtils { + + /** + * Private Constructor to prevent + * instantiation of the class. + */ + private GoraUtils() { + + // utility Class + } + + /** + * Utility method to construct a new query from the exchange + * + * NOTE: values used in order construct the query + * should be stored in the "in" message headers. + * + * @param dataStore + * @param conf + * @return + * @throws ClassNotFoundException + * @throws IllegalAccessException + * @throws NoSuchMethodException + * @throws InvocationTargetException + */ + public static Query constractQueryFromConfiguration(final DataStore dataStore, final GoraConfiguration conf) + throws ClassNotFoundException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { + + final Query query = dataStore.newQuery(); + + if (configurationExist(GoraAttribute.GORA_QUERY_START_TIME, conf)) { + query.setStartTime(getAttributeAsLong(GoraAttribute.GORA_QUERY_START_TIME, conf)); + } + + if (configurationExist(GoraAttribute.GORA_QUERY_END_TIME, conf)) { + query.setEndTime(getAttributeAsLong(GoraAttribute.GORA_QUERY_END_TIME, conf)); + } + + if (configurationExist(GoraAttribute.GORA_QUERY_LIMIT, conf)) { + query.setLimit(getAttributeAsLong(GoraAttribute.GORA_QUERY_LIMIT, conf)); + } + + if (configurationExist(GoraAttribute.GORA_QUERY_TIME_RANGE_FROM, conf) + && configurationExist(GoraAttribute.GORA_QUERY_TIME_RANGE_TO, conf)) { + query.setTimeRange(getAttributeAsLong(GoraAttribute.GORA_QUERY_TIME_RANGE_FROM, conf), + getAttributeAsLong(GoraAttribute.GORA_QUERY_TIME_RANGE_TO, conf)); + } + + if (configurationExist(GoraAttribute.GORA_QUERY_TIMESTAMP, conf)) { + query.setTimestamp(getAttributeAsLong(GoraAttribute.GORA_QUERY_TIMESTAMP, conf)); + } + + if (configurationExist(GoraAttribute.GORA_QUERY_START_KEY, conf)) { + query.setStartKey(getAttribute(GoraAttribute.GORA_QUERY_START_KEY, conf)); + } + + if (configurationExist(GoraAttribute.GORA_QUERY_END_KEY, conf)) { + query.setEndKey(getAttribute(GoraAttribute.GORA_QUERY_END_KEY, conf)); + } + + if (configurationExist(GoraAttribute.GORA_QUERY_KEY_RANGE_FROM, conf) + && configurationExist(GoraAttribute.GORA_QUERY_KEY_RANGE_TO, conf)) { + query.setKeyRange(getAttribute(GoraAttribute.GORA_QUERY_KEY_RANGE_FROM, conf), + getAttribute(GoraAttribute.GORA_QUERY_KEY_RANGE_TO, conf)); + } + + return query; + } + + /** + * Utility method to construct a new query from the exchange + * + * NOTE: values used in order construct the query + * should be stored in the "in" message headers. + * + * @param propertiesMap + * @param dataStore + * @param conf + * @return + * @throws ClassNotFoundException + */ + public static Query constractQueryFromPropertiesMap(final Map propertiesMap, + final DataStore dataStore, + final GoraConfiguration conf) throws ClassNotFoundException { + + + final Query query = dataStore.newQuery(); + + if (propertyExist(GoraAttribute.GORA_QUERY_START_TIME, propertiesMap)) { + query.setStartTime(getPropertyAsLong(GoraAttribute.GORA_QUERY_START_TIME, propertiesMap)); + } + + if (propertyExist(GoraAttribute.GORA_QUERY_END_TIME, propertiesMap)) { + query.setEndTime(getPropertyAsLong(GoraAttribute.GORA_QUERY_END_TIME, propertiesMap)); + } + + if (propertyExist(GoraAttribute.GORA_QUERY_LIMIT, propertiesMap)) { + query.setLimit(getPropertyAsLong(GoraAttribute.GORA_QUERY_LIMIT, propertiesMap)); + } + + if (propertyExist(GoraAttribute.GORA_QUERY_TIME_RANGE_FROM, propertiesMap) + && propertyExist(GoraAttribute.GORA_QUERY_TIME_RANGE_TO, propertiesMap)) { + query.setTimeRange(getPropertyAsLong(GoraAttribute.GORA_QUERY_TIME_RANGE_FROM, propertiesMap), + getPropertyAsLong(GoraAttribute.GORA_QUERY_TIME_RANGE_TO, propertiesMap)); + } + + if (propertyExist(GoraAttribute.GORA_QUERY_TIMESTAMP, propertiesMap)) { + query.setTimestamp(getPropertyAsLong(GoraAttribute.GORA_QUERY_TIMESTAMP, propertiesMap)); + } + + if (propertyExist(GoraAttribute.GORA_QUERY_START_KEY, propertiesMap)) { + query.setStartKey(getProperty(GoraAttribute.GORA_QUERY_START_KEY, propertiesMap)); + } + + if (propertyExist(GoraAttribute.GORA_QUERY_END_KEY, propertiesMap)) { + query.setStartKey(getProperty(GoraAttribute.GORA_QUERY_END_KEY, propertiesMap)); + } + + if (propertyExist(GoraAttribute.GORA_QUERY_KEY_RANGE_FROM, propertiesMap) + && propertyExist(GoraAttribute.GORA_QUERY_KEY_RANGE_TO, propertiesMap)) { + query.setKeyRange(getProperty(GoraAttribute.GORA_QUERY_KEY_RANGE_FROM, propertiesMap), + getProperty(GoraAttribute.GORA_QUERY_KEY_RANGE_TO, propertiesMap)); + } + + return query; + } + + /** + * Utility method to check if a value exist in the configuration class + * + * NOTE: + * Checks only if is not null + * + * @param attr + * @param conf + * @return + * @throws IllegalAccessException + * @throws NoSuchMethodException + * @throws InvocationTargetException + */ + protected static boolean configurationExist(final GoraAttribute attr, + final GoraConfiguration conf) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException { + + return PropertyUtils.getSimpleProperty(conf, attr.value) != null; + } + + /** + * Utility method to check if a value exist in the properties map + * + * @param attr + * @param propertiesMap + * @return + */ + protected static boolean propertyExist(final GoraAttribute attr, + final Map propertiesMap) { + + return propertiesMap.containsKey(attr.value); + } + + + /** + * Utility method to extract value from configuration + * + * @param attr + * @param conf + * @return + * @throws IllegalAccessException + * @throws NoSuchMethodException + * @throws InvocationTargetException + */ + protected static Object getAttribute(final GoraAttribute attr, + final GoraConfiguration conf) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException { + + return PropertyUtils.getSimpleProperty(conf, attr.value); + } + + /** + * Utility method to extract value from configuration as String + * + * @param attr + * @param conf + * @return + * @throws IllegalAccessException + * @throws NoSuchMethodException + * @throws InvocationTargetException + */ + protected static String getAttributeAsString(final GoraAttribute attr, + final GoraConfiguration conf) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException { + + return String.valueOf(getAttribute(attr, conf)); + } + + + /** + * Utility method to extract value from configuration as Long + * + * @param attr + * @param conf + * @return + * @throws IllegalAccessException + * @throws NoSuchMethodException + * @throws InvocationTargetException + */ + protected static Long getAttributeAsLong(final GoraAttribute attr, + final GoraConfiguration conf) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException { + + return Long.parseLong(getAttributeAsString(attr, conf)); + } + + /** + * Utility method to extract value of a map + * + * @param attr + * @param propertiesMap + * @return + */ + protected static Object getProperty(final GoraAttribute attr, + final Map propertiesMap) { + + return propertiesMap.get(attr.value); + } + + /** + * Utility method to extract value of a map as String + * + * @param attr + * @param propertiesMap + * @return + */ + protected static String getPropertyAsString(final GoraAttribute attr, + final Map propertiesMap) { + + return String.valueOf(getProperty(attr, propertiesMap)); + } + + /** + * Utility method to extract value of a map as long + * + * @param attr + * @param propertiesMap + * @return + */ + protected static Long getPropertyAsLong(final GoraAttribute attr, + final Map propertiesMap) { + + return Long.parseLong(getPropertyAsString(attr, propertiesMap)); + } + + + /** + * Utility method to extract GORA key from the exchange + * + * NOTE: key value expected to be stored + * in the "in" message headers. + * + * @param exchange The Camel Exchange + * @return The key + */ + public static Object getKeyFromExchange(Exchange exchange) { + + final Object key = exchange.getIn().getHeader(GoraAttribute.GORA_KEY.value); + + checkNotNull(key, "Key should not be null!"); + return key; + } + + /** + * Utility method to extract the value from the exchange + * + * NOTE: the value expected to be instance + * of persistent type. + * + * @param exchange The Camel Exchange + * @return The value + */ + public static Persistent getValueFromExchange(Exchange exchange) { + + return exchange.getIn().getBody(Persistent.class); + } + +} diff --git a/components/camel-gora/src/main/resources/META-INF/LICENSE.txt b/components/camel-gora/src/main/resources/META-INF/LICENSE.txt new file mode 100644 index 0000000000000..6b0b1270ff0ca --- /dev/null +++ b/components/camel-gora/src/main/resources/META-INF/LICENSE.txt @@ -0,0 +1,203 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. + diff --git a/components/camel-gora/src/main/resources/META-INF/NOTICE.txt b/components/camel-gora/src/main/resources/META-INF/NOTICE.txt new file mode 100644 index 0000000000000..2e215bf2e6b1f --- /dev/null +++ b/components/camel-gora/src/main/resources/META-INF/NOTICE.txt @@ -0,0 +1,11 @@ + ========================================================================= + == NOTICE file corresponding to the section 4 d of == + == the Apache License, Version 2.0, == + == in this case for the Apache Camel distribution. == + ========================================================================= + + This product includes software developed by + The Apache Software Foundation (http://www.apache.org/). + + Please read the different LICENSE files present in the licenses directory of + this distribution. diff --git a/components/camel-gora/src/main/resources/META-INF/services/org/apache/camel/component/gora b/components/camel-gora/src/main/resources/META-INF/services/org/apache/camel/component/gora new file mode 100644 index 0000000000000..4cb9abb656921 --- /dev/null +++ b/components/camel-gora/src/main/resources/META-INF/services/org/apache/camel/component/gora @@ -0,0 +1,18 @@ +## ------------------------------------------------------------------------ +## 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. +## ------------------------------------------------------------------------ + +class=org.apache.camel.component.gora.GoraComponent diff --git a/components/camel-gora/src/test/java/org/apache/camel/component/gora/GoraConfigurationTest.java b/components/camel-gora/src/test/java/org/apache/camel/component/gora/GoraConfigurationTest.java new file mode 100644 index 0000000000000..ef20e31a850a5 --- /dev/null +++ b/components/camel-gora/src/test/java/org/apache/camel/component/gora/GoraConfigurationTest.java @@ -0,0 +1,77 @@ +/** + * 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.component.gora; + +import org.junit.Test; + +/** + * GORA Configuration Tests + * + */ +public class GoraConfigurationTest { + + + @Test(expected = IllegalArgumentException.class) + public void setKeyClassClassShouldThrowExceptionIfNull() { + + final GoraConfiguration conf = new GoraConfiguration(); + conf.setValueClass(null); + } + + @Test(expected = IllegalArgumentException.class) + public void setKeyClassShouldThrowExceptionIfEmpty() { + + final GoraConfiguration conf = new GoraConfiguration(); + conf.setValueClass(""); + } + + @Test(expected = IllegalArgumentException.class) + public void setValueClassClassShouldThrowExceptionIfNull() { + + final GoraConfiguration conf = new GoraConfiguration(); + conf.setValueClass(null); + } + + @Test(expected = IllegalArgumentException.class) + public void setValueClassClassShouldThrowExceptionIfEmpty() { + + final GoraConfiguration conf = new GoraConfiguration(); + conf.setValueClass(""); + } + + @Test(expected = IllegalArgumentException.class) + public void setDataStoreClassShouldThrowExceptionIfNull() { + + final GoraConfiguration conf = new GoraConfiguration(); + conf.setDataStoreClass(null); + } + + @Test(expected = IllegalArgumentException.class) + public void setDataStoreClassShouldThrowExceptionIfEmpty() { + + final GoraConfiguration conf = new GoraConfiguration(); + conf.setDataStoreClass(""); + } + + @Test(expected = NullPointerException.class) + public void setHadoopConfigurationShouldThrowExceptionIfNull() { + + final GoraConfiguration conf = new GoraConfiguration(); + conf.setHadoopConfiguration(null); + } +} diff --git a/components/camel-gora/src/test/java/org/apache/camel/component/gora/GoraConsumerTest.java b/components/camel-gora/src/test/java/org/apache/camel/component/gora/GoraConsumerTest.java new file mode 100644 index 0000000000000..f2d22b0f7d08d --- /dev/null +++ b/components/camel-gora/src/test/java/org/apache/camel/component/gora/GoraConsumerTest.java @@ -0,0 +1,97 @@ +/** + * 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.component.gora; + +import java.lang.reflect.InvocationTargetException; + +import org.apache.camel.Exchange; +import org.apache.camel.ExchangePattern; +import org.apache.camel.Message; +import org.apache.camel.Processor; +import org.apache.gora.query.Query; +import org.apache.gora.store.DataStore; +import org.junit.Before; +import org.junit.Test; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * GORA Consumer Tests + * + */ +public class GoraConsumerTest extends GoraTestSupport { + + /** + * Mock CamelExchange + */ + private Exchange mockCamelExchange; + + /** + * Mock Gora Endpoint + */ + private GoraEndpoint mockGoraEndpoint; + + /** + * Mock Gora Configuration + */ + private GoraConfiguration mockGoraConfiguration; + + /** + * Mock Camel Message + */ + private Message mockCamelMessage; + + /** + * Mock Gora DataStore + */ + private DataStore mockDatastore; + + /** + * Mock Processor + */ + private Processor mockGoraProcessor; + + + @Before + public void setUp() { + + //setup mocks + mockCamelExchange = mock(Exchange.class); + mockGoraEndpoint = mock(GoraEndpoint.class); + mockGoraConfiguration = mock(GoraConfiguration.class); + mockCamelMessage = mock(Message.class); + mockDatastore = mock(DataStore.class); + + + //setup default conditions + when(mockCamelExchange.getIn()).thenReturn(mockCamelMessage); + when(mockCamelExchange.getPattern()).thenReturn(ExchangePattern.InOnly); + } + + + @Test + public void consumerInstantiationWithMocksShouldSucceed() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { + + + final Query mockQuery = mock(Query.class); + when(mockDatastore.newQuery()).thenReturn(mockQuery); + GoraConsumer goraConsumer = new GoraConsumer(mockGoraEndpoint, mockGoraProcessor, mockGoraConfiguration, mockDatastore); + } + +} diff --git a/components/camel-gora/src/test/java/org/apache/camel/component/gora/GoraProducerTest.java b/components/camel-gora/src/test/java/org/apache/camel/component/gora/GoraProducerTest.java new file mode 100644 index 0000000000000..4012e82f99668 --- /dev/null +++ b/components/camel-gora/src/test/java/org/apache/camel/component/gora/GoraProducerTest.java @@ -0,0 +1,305 @@ +/** + * 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.component.gora; + +import java.util.Map; + +import org.apache.camel.Exchange; +import org.apache.camel.ExchangePattern; +import org.apache.camel.Message; +import org.apache.camel.component.gora.utils.GoraUtils; +import org.apache.gora.persistency.Persistent; +import org.apache.gora.query.Query; +import org.apache.gora.query.impl.QueryBase; +import org.apache.gora.store.DataStore; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.atMost; +import static org.mockito.Mockito.verify; +import static org.mockito.internal.verification.VerificationModeFactory.times; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.mockStatic; +import static org.powermock.api.mockito.PowerMockito.verifyStatic; +import static org.powermock.api.mockito.PowerMockito.when; + +/** + * GORA Producer Tests + * + * TODO: NOTE: Query methods does not yet has tests + * + */ +@RunWith(PowerMockRunner.class) +@PrepareForTest(GoraUtils.class) +public class GoraProducerTest extends GoraTestSupport { + + /** + * Mock CamelExchange + */ + private Exchange mockCamelExchange; + + /** + * Mock Gora Endpoint + */ + private GoraEndpoint mockGoraEndpoint; + + /** + * Mock Gora Configuration + */ + private GoraConfiguration mockGoraConfiguration; + + /** + * Mock Camel Message + */ + private Message mockCamelMessage; + + /** + * Mock Gora DataStore + */ + private DataStore mockDatastore; + + @Before + public void setUp() { + + //setup mocks + mockCamelExchange = mock(Exchange.class); + mockGoraEndpoint = mock(GoraEndpoint.class); + mockGoraConfiguration = mock(GoraConfiguration.class); + mockCamelMessage = mock(Message.class); + mockDatastore = mock(DataStore.class); + + //setup default conditions + when(mockCamelExchange.getIn()).thenReturn(mockCamelMessage); + when(mockCamelExchange.getPattern()).thenReturn(ExchangePattern.InOnly); + } + + @Test(expected = RuntimeException.class) + public void processShouldThrowExceptionIfOperationIsNull() throws Exception { + + final GoraProducer producer = new GoraProducer(mockGoraEndpoint, mockGoraConfiguration, mockDatastore); + producer.process(mockCamelExchange); + } + + @Test(expected = RuntimeException.class) + public void shouldThrowExceptionIfOperationIsUnknown() throws Exception { + + + when(mockCamelExchange.getIn()).thenReturn(mockCamelMessage); + when(mockCamelMessage.getHeader(GoraAttribute.GORA_OPERATION.value)).thenReturn("dah"); + + final GoraProducer producer = new GoraProducer(mockGoraEndpoint, mockGoraConfiguration, mockDatastore); + producer.process(mockCamelExchange); + + verify(mockCamelExchange, atMost(1)).getIn(); + verify(mockCamelMessage, atMost(1)).getHeader(GoraAttribute.GORA_OPERATION.value); + } + + @Test + public void shouldInvokeDastorePut() throws Exception { + + when(mockCamelExchange.getIn()).thenReturn(mockCamelMessage); + when(mockCamelMessage.getHeader(GoraAttribute.GORA_OPERATION.value)).thenReturn("PUT"); + + final Long sampleKey = new Long(2); + when(mockCamelMessage.getHeader(GoraAttribute.GORA_KEY.value)).thenReturn(sampleKey); + + final Persistent sampleValue = mock(Persistent.class); + when(mockCamelMessage.getBody(Persistent.class)).thenReturn(sampleValue); + + final Message outMessage = mock(Message.class); + when(mockCamelExchange.getOut()).thenReturn(outMessage); + + final GoraProducer producer = new GoraProducer(mockGoraEndpoint, mockGoraConfiguration, mockDatastore); + producer.process(mockCamelExchange); + + verify(mockCamelExchange, atLeastOnce()).getIn(); + verify(mockCamelMessage, atLeastOnce()).getHeader(GoraAttribute.GORA_OPERATION.value); + verify(mockCamelMessage, atLeastOnce()).getHeader(GoraAttribute.GORA_KEY.value); + verify(mockCamelMessage, atLeastOnce()).getBody(Persistent.class); + verify(mockDatastore, atMost(1)).put(sampleKey, sampleValue); + } + + @Test + public void shouldInvokeDastoreGet() throws Exception { + + when(mockCamelExchange.getIn()).thenReturn(mockCamelMessage); + when(mockCamelMessage.getHeader(GoraAttribute.GORA_OPERATION.value)).thenReturn("get"); + + final Long sampleKey = new Long(2); + when(mockCamelMessage.getHeader(GoraAttribute.GORA_KEY.value)).thenReturn(sampleKey); + + final Message outMessage = mock(Message.class); + when(mockCamelExchange.getOut()).thenReturn(outMessage); + + final GoraProducer producer = new GoraProducer(mockGoraEndpoint, mockGoraConfiguration, mockDatastore); + producer.process(mockCamelExchange); + + verify(mockCamelExchange, atLeastOnce()).getIn(); + verify(mockCamelMessage, atLeastOnce()).getHeader(GoraAttribute.GORA_OPERATION.value); + verify(mockCamelMessage, atLeastOnce()).getHeader(GoraAttribute.GORA_KEY.value); + verify(mockDatastore, atMost(1)).get(sampleKey); + } + + @Test + public void shouldInvokeDatastoreDelete() throws Exception { + + when(mockCamelExchange.getIn()).thenReturn(mockCamelMessage); + when(mockCamelMessage.getHeader(GoraAttribute.GORA_OPERATION.value)).thenReturn("dEletE"); + + final Long sampleKey = new Long(2); + when(mockCamelMessage.getHeader(GoraAttribute.GORA_KEY.value)).thenReturn(sampleKey); + + final Message outMessage = mock(Message.class); + when(mockCamelExchange.getOut()).thenReturn(outMessage); + + final GoraProducer producer = new GoraProducer(mockGoraEndpoint, mockGoraConfiguration, mockDatastore); + producer.process(mockCamelExchange); + + verify(mockCamelExchange, atLeastOnce()).getIn(); + verify(mockCamelMessage, atLeastOnce()).getHeader(GoraAttribute.GORA_OPERATION.value); + verify(mockCamelMessage, atLeastOnce()).getHeader(GoraAttribute.GORA_KEY.value); + verify(mockDatastore, atMost(1)).delete(sampleKey); + } + + @Test + public void shouldInvokeDastoreSchemaExists() throws Exception { + + when(mockCamelExchange.getIn()).thenReturn(mockCamelMessage); + when(mockCamelMessage.getHeader(GoraAttribute.GORA_OPERATION.value)).thenReturn("schemaExists"); + + final Message outMessage = mock(Message.class); + when(mockCamelExchange.getOut()).thenReturn(outMessage); + + final GoraProducer producer = new GoraProducer(mockGoraEndpoint, mockGoraConfiguration, mockDatastore); + producer.process(mockCamelExchange); + + verify(mockCamelExchange, atLeastOnce()).getIn(); + verify(mockCamelMessage, atLeastOnce()).getHeader(GoraAttribute.GORA_OPERATION.value); + verify(mockDatastore, atMost(1)).schemaExists(); + } + + @Test + public void shouldInvokeDastoreCreateSchema() throws Exception { + + when(mockCamelExchange.getIn()).thenReturn(mockCamelMessage); + when(mockCamelMessage.getHeader(GoraAttribute.GORA_OPERATION.value)).thenReturn("createSchema"); + + final Message outMessage = mock(Message.class); + when(mockCamelExchange.getOut()).thenReturn(outMessage); + + final GoraProducer producer = new GoraProducer(mockGoraEndpoint, mockGoraConfiguration, mockDatastore); + producer.process(mockCamelExchange); + + verify(mockCamelExchange, atLeastOnce()).getIn(); + verify(mockCamelMessage, atLeastOnce()).getHeader(GoraAttribute.GORA_OPERATION.value); + verify(mockDatastore, atMost(1)).createSchema(); + } + + @Test + public void shouldInvokeDastoreGetSchemaName() throws Exception { + + when(mockCamelExchange.getIn()).thenReturn(mockCamelMessage); + when(mockCamelMessage.getHeader(GoraAttribute.GORA_OPERATION.value)).thenReturn("GetSchemANamE"); + + + final Message outMessage = mock(Message.class); + when(mockCamelExchange.getOut()).thenReturn(outMessage); + + final GoraProducer producer = new GoraProducer(mockGoraEndpoint, mockGoraConfiguration, mockDatastore); + producer.process(mockCamelExchange); + + verify(mockCamelExchange, atLeastOnce()).getIn(); + verify(mockCamelMessage, atLeastOnce()).getHeader(GoraAttribute.GORA_OPERATION.value); + verify(mockDatastore, atMost(1)).getSchemaName(); + } + + @Test + public void shouldInvokeDatastoreDeleteSchema() throws Exception { + + when(mockCamelExchange.getIn()).thenReturn(mockCamelMessage); + when(mockCamelMessage.getHeader(GoraAttribute.GORA_OPERATION.value)).thenReturn("DeleteSChEmA"); + + + final Message outMessage = mock(Message.class); + when(mockCamelExchange.getOut()).thenReturn(outMessage); + + final GoraProducer producer = new GoraProducer(mockGoraEndpoint, mockGoraConfiguration, mockDatastore); + producer.process(mockCamelExchange); + + verify(mockCamelExchange, atLeastOnce()).getIn(); + verify(mockCamelMessage, atLeastOnce()).getHeader(GoraAttribute.GORA_OPERATION.value); + verify(mockDatastore, atMost(1)).deleteSchema(); + } + + @Test + public void shouldInvokeDatastoreQuery() throws Exception { + + when(mockCamelExchange.getIn()).thenReturn(mockCamelMessage); + when(mockCamelMessage.getHeader(GoraAttribute.GORA_OPERATION.value)).thenReturn("query"); + + final Map mockProperties = mock(Map.class); + when(mockCamelMessage.getHeaders()).thenReturn(mockProperties); + + final Message outMessage = mock(Message.class); + when(mockCamelExchange.getOut()).thenReturn(outMessage); + + mockStatic(GoraUtils.class); + + final Query mockQuery = mock(QueryBase.class); + when(GoraUtils.constractQueryFromPropertiesMap(mockProperties, mockDatastore, mockGoraConfiguration)).thenReturn(mockQuery); + + final GoraProducer producer = new GoraProducer(mockGoraEndpoint, mockGoraConfiguration, mockDatastore); + producer.process(mockCamelExchange); + + verify(mockCamelExchange, atLeastOnce()).getIn(); + verify(mockCamelMessage, atLeastOnce()).getHeader(GoraAttribute.GORA_OPERATION.value); + verify(mockQuery, atLeastOnce()).execute(); + verifyStatic(times(1)); + } + + @Test + public void shouldInvokeDatastoreDeleteByQuery() throws Exception { + + when(mockCamelExchange.getIn()).thenReturn(mockCamelMessage); + when(mockCamelMessage.getHeader(GoraAttribute.GORA_OPERATION.value)).thenReturn("deleteByQuery"); + + final Map mockProperties = mock(Map.class); + when(mockCamelMessage.getHeaders()).thenReturn(mockProperties); + + final Message outMessage = mock(Message.class); + when(mockCamelExchange.getOut()).thenReturn(outMessage); + + mockStatic(GoraUtils.class); + + final Query mockQuery = mock(QueryBase.class); + when(GoraUtils.constractQueryFromPropertiesMap(mockProperties, mockDatastore, mockGoraConfiguration)).thenReturn(mockQuery); + + final GoraProducer producer = new GoraProducer(mockGoraEndpoint, mockGoraConfiguration, mockDatastore); + producer.process(mockCamelExchange); + + verify(mockCamelExchange, atLeastOnce()).getIn(); + verify(mockCamelMessage, atLeastOnce()).getHeader(GoraAttribute.GORA_OPERATION.value); + verify(mockDatastore, atMost(1)).deleteByQuery(mockQuery); + verifyStatic(times(1)); + } + +} diff --git a/components/camel-gora/src/test/java/org/apache/camel/component/gora/GoraTestSupport.java b/components/camel-gora/src/test/java/org/apache/camel/component/gora/GoraTestSupport.java new file mode 100644 index 0000000000000..3d11e808da71f --- /dev/null +++ b/components/camel-gora/src/test/java/org/apache/camel/component/gora/GoraTestSupport.java @@ -0,0 +1,28 @@ +/** + * 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.component.gora; + +import org.apache.camel.test.junit4.CamelTestSupport; + +/** + * GORA Test Support + * + */ +public class GoraTestSupport extends CamelTestSupport { + //TODO +} diff --git a/components/camel-gora/src/test/java/org/apache/camel/component/gora/utils/GoraUtilsTest.java b/components/camel-gora/src/test/java/org/apache/camel/component/gora/utils/GoraUtilsTest.java new file mode 100644 index 0000000000000..56ecfb477a527 --- /dev/null +++ b/components/camel-gora/src/test/java/org/apache/camel/component/gora/utils/GoraUtilsTest.java @@ -0,0 +1,54 @@ +/** + * 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.component.gora.utils; + +import org.apache.camel.component.gora.GoraAttribute; +import org.apache.camel.component.gora.GoraConfiguration; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * GORA Utils Tests + * + */ +public class GoraUtilsTest { + + @Test + public void configurationExistShouldSucceedtIfMethodExist() throws Exception { + + final GoraConfiguration conf = new GoraConfiguration(); + assertTrue(GoraUtils.configurationExist(GoraAttribute.GORA_QUERY_LIMIT, conf)); + } + + @Test(expected = NoSuchMethodException.class) + public void configurationExistShouldThrowExceptionIfMethodDoesNotExist() throws Exception { + + final GoraConfiguration conf = new GoraConfiguration(); + GoraUtils.configurationExist(GoraAttribute.GORA_KEY, conf); + } + + @Test + public void getAttributeAsLongShouldSReturnTheCorrectValue() throws Exception { + + final GoraConfiguration conf = new GoraConfiguration(); + conf.setLimit(3L); + assertEquals(new Long(3), GoraUtils.getAttributeAsLong(GoraAttribute.GORA_QUERY_LIMIT, conf)); + } +} diff --git a/components/camel-infinispan/pom.xml b/components/camel-infinispan/pom.xml index d34043fc8c738..70951863f5011 100644 --- a/components/camel-infinispan/pom.xml +++ b/components/camel-infinispan/pom.xml @@ -28,7 +28,7 @@ camel-infinispan bundle - Camel-Infinispan Component + Camel :: Infinispan Camel Infinispan support diff --git a/components/camel-jms/src/main/java/org/apache/camel/component/jms/JmsEndpoint.java b/components/camel-jms/src/main/java/org/apache/camel/component/jms/JmsEndpoint.java index 17204b5b53b63..af15397830f7d 100644 --- a/components/camel-jms/src/main/java/org/apache/camel/component/jms/JmsEndpoint.java +++ b/components/camel-jms/src/main/java/org/apache/camel/component/jms/JmsEndpoint.java @@ -1148,11 +1148,16 @@ public void setReplyToType(String replyToType) { configuration.setReplyToType(type); } - @ManagedAttribute(description = "Camel id") + @ManagedAttribute(description = "Camel ID") public String getCamelId() { return getCamelContext().getName(); } + @ManagedAttribute(description = "Camel ManagementName") + public String getCamelManagementName() { + return getCamelContext().getManagementName(); + } + @ManagedAttribute(description = "Endpoint Uri", mask = true) @Override public String getEndpointUri() { diff --git a/components/camel-paxlogging/src/main/java/org/apache/camel/component/paxlogging/PaxLoggingConsumer.java b/components/camel-paxlogging/src/main/java/org/apache/camel/component/paxlogging/PaxLoggingConsumer.java index 7e9b44d8ca167..51eb2dc852eae 100644 --- a/components/camel-paxlogging/src/main/java/org/apache/camel/component/paxlogging/PaxLoggingConsumer.java +++ b/components/camel-paxlogging/src/main/java/org/apache/camel/component/paxlogging/PaxLoggingConsumer.java @@ -53,6 +53,8 @@ public PaxLoggingConsumer(PaxLoggingEndpoint endpoint, Processor processor) { } public void doAppend(final PaxLoggingEvent paxLoggingEvent) { + // in order to "force" the copy of properties (especially the MDC ones) in the local thread + paxLoggingEvent.getProperties(); executor.execute(new Runnable() { public void run() { sendExchange(paxLoggingEvent); diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/RestResources.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/RestResources.java index 9e7c6447718ad..ce108b182009e 100644 --- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/RestResources.java +++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/RestResources.java @@ -32,6 +32,8 @@ public class RestResources extends AbstractDTOBase { private String chatter; private String recent; private String tooling; + private String licensing; + private String analytics; public String getSobjects() { return sobjects; @@ -97,4 +99,19 @@ public void setTooling(String tooling) { this.tooling = tooling; } + public String getLicensing() { + return licensing; + } + + public void setLicensing(String licensing) { + this.licensing = licensing; + } + + public String getAnalytics() { + return analytics; + } + + public void setAnalytics(String analytics) { + this.analytics = analytics; + } } diff --git a/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/CamelSalesforceMojoIntegrationTest.java b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/CamelSalesforceMojoIntegrationTest.java index c6df2aced9e82..406ce5f6aec56 100644 --- a/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/CamelSalesforceMojoIntegrationTest.java +++ b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/CamelSalesforceMojoIntegrationTest.java @@ -19,6 +19,7 @@ import java.io.*; import java.util.Properties; +import org.apache.camel.component.salesforce.SalesforceEndpointConfig; import org.apache.maven.plugin.logging.SystemStreamLog; import org.junit.Assert; import org.junit.Test; @@ -37,12 +38,12 @@ public void testExecute() throws Exception { setLoginProperties(mojo); // set defaults - mojo.version = "27.0"; + mojo.version = System.getProperty("apiVersion", SalesforceEndpointConfig.DEFAULT_VERSION); mojo.outputDirectory = new File("target/generated-sources/camel-salesforce"); mojo.packageName = "org.apache.camel.salesforce.dto"; // set code generation properties - mojo.includePattern = "(.*__c)|(PushTopic)"; + mojo.includePattern = "(.*__c)|(PushTopic)|(Document)"; // remove generated code directory if (mojo.outputDirectory.exists()) { diff --git a/components/camel-zookeeper/src/main/java/org/apache/camel/component/zookeeper/ZooKeeperEndpoint.java b/components/camel-zookeeper/src/main/java/org/apache/camel/component/zookeeper/ZooKeeperEndpoint.java index 0e26004780897..52003667f6455 100644 --- a/components/camel-zookeeper/src/main/java/org/apache/camel/component/zookeeper/ZooKeeperEndpoint.java +++ b/components/camel-zookeeper/src/main/java/org/apache/camel/component/zookeeper/ZooKeeperEndpoint.java @@ -21,6 +21,7 @@ import org.apache.camel.Consumer; import org.apache.camel.Processor; import org.apache.camel.Producer; +import org.apache.camel.ServiceStatus; import org.apache.camel.api.management.ManagedAttribute; import org.apache.camel.api.management.ManagedOperation; import org.apache.camel.api.management.ManagedResource; @@ -66,6 +67,32 @@ ZooKeeperConnectionManager getConnectionManager() { return connectionManager; } + @ManagedAttribute(description = "Camel ID") + public String getCamelId() { + return getCamelContext().getName(); + } + + @ManagedAttribute(description = "Camel ManagementName") + public String getCamelManagementName() { + return getCamelContext().getManagementName(); + } + + @ManagedAttribute(description = "Endpoint Uri", mask = true) + @Override + public String getEndpointUri() { + return super.getEndpointUri(); + } + + @ManagedAttribute(description = "Service State") + public String getState() { + ServiceStatus status = this.getStatus(); + // if no status exists then its stopped + if (status == null) { + status = ServiceStatus.Stopped; + } + return status.name(); + } + @ManagedAttribute public void setPath(String path) { getConfiguration().setPath(path); diff --git a/examples/camel-example-twitter-websocket-blueprint/README.txt b/examples/camel-example-twitter-websocket-blueprint/README.txt index 4d7433b4b3702..918d31468c8ca 100644 --- a/examples/camel-example-twitter-websocket-blueprint/README.txt +++ b/examples/camel-example-twitter-websocket-blueprint/README.txt @@ -18,13 +18,14 @@ You will need to install this example first to your local maven repository with: This example requires running in Apache Karaf / ServiceMix -To install Apache Camel in Karaf you type in the shell (we use version 2.12.0): +To install Apache Camel in Karaf you type in the shell (as an example here we make use of +Camel version 2.12.0): features:chooseurl camel 2.12.0 - features:install camel First you need to install the following features in Karaf/ServiceMix with: + features:install camel-blueprint features:install camel-twitter features:install camel-websocket diff --git a/examples/pom.xml b/examples/pom.xml index bbed46030f85b..78adf10fc1f9f 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -82,6 +82,9 @@ + + + ${project.artifactId} false diff --git a/parent/pom.xml b/parent/pom.xml index cb05bb8617c8d..7b6383673169e 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -43,6 +43,7 @@ 3.4_2 1.0_6 1.5.7 + 0.4-SNAPSHOT 0.7.2 1.0.0 1.1.0 @@ -80,6 +81,7 @@ 2.3.1_2 2.3.1 1.8.3_1 + 1.8.3 1.8 3.2.1 1.5 @@ -324,6 +326,7 @@ 1.0-alpha-48 1.5.6 0.2.1 + 1.5.1 2.3.0_3 2.3.0 0.22_1 diff --git a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/AbstractRouteCommand.java b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/AbstractRouteCommand.java index 756243c840a31..c2edac08d6986 100644 --- a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/AbstractRouteCommand.java +++ b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/AbstractRouteCommand.java @@ -24,23 +24,16 @@ import org.apache.camel.Route; import org.apache.camel.karaf.commands.internal.RegexUtil; import org.apache.felix.gogo.commands.Argument; -import org.apache.karaf.shell.console.OsgiCommandSupport; import static org.apache.camel.util.CamelContextHelper.getRouteStartupOrder; -public abstract class AbstractRouteCommand extends OsgiCommandSupport { +public abstract class AbstractRouteCommand extends CamelCommandSupport { @Argument(index = 0, name = "route", description = "The Camel route ID or a wildcard expression", required = true, multiValued = false) String route; @Argument(index = 1, name = "context", description = "The Camel context name.", required = false, multiValued = false) String context; - private CamelController camelController; - - public void setCamelController(CamelController camelController) { - this.camelController = camelController; - } - public abstract void executeOnRoute(CamelContext camelContext, Route camelRoute) throws Exception; public Object doExecute() throws Exception { diff --git a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/BacklogTracerDump.java b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/BacklogTracerDump.java index 8945951ee530f..429e0a5d667a4 100644 --- a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/BacklogTracerDump.java +++ b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/BacklogTracerDump.java @@ -30,13 +30,12 @@ import org.apache.felix.gogo.commands.Argument; import org.apache.felix.gogo.commands.Command; import org.apache.felix.gogo.commands.Option; -import org.apache.karaf.shell.console.OsgiCommandSupport; /** * Command to use the Backlog Tracer. */ @Command(scope = "camel", name = "backlog-tracer-dump", description = "Dumps traced messages from the Backlog tracer") -public class BacklogTracerDump extends OsgiCommandSupport { +public class BacklogTracerDump extends CamelCommandSupport { @Argument(index = 0, name = "context", description = "The name of the Camel context.", required = true, multiValued = false) String context; @@ -50,12 +49,6 @@ public class BacklogTracerDump extends OsgiCommandSupport { @Option(name = "--bodySize", aliases = "-bs", description = "To limit the body size when using text format", required = false, multiValued = false) Integer bodySize; - private CamelController camelController; - - public void setCamelController(CamelController camelController) { - this.camelController = camelController; - } - @Override protected Object doExecute() throws Exception { CamelContext camel = camelController.getCamelContext(context); diff --git a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/BacklogTracerInfo.java b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/BacklogTracerInfo.java index 47bc15f413e88..7ef9af96d0762 100644 --- a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/BacklogTracerInfo.java +++ b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/BacklogTracerInfo.java @@ -20,23 +20,16 @@ import org.apache.camel.processor.interceptor.BacklogTracer; import org.apache.felix.gogo.commands.Argument; import org.apache.felix.gogo.commands.Command; -import org.apache.karaf.shell.console.OsgiCommandSupport; /** * Command to use the Backlog Tracer. */ @Command(scope = "camel", name = "backlog-tracer-info", description = "Displays the current status of the Backlog tracer") -public class BacklogTracerInfo extends OsgiCommandSupport { +public class BacklogTracerInfo extends CamelCommandSupport { @Argument(index = 0, name = "context", description = "The name of the Camel context.", required = true, multiValued = false) String context; - private CamelController camelController; - - public void setCamelController(CamelController camelController) { - this.camelController = camelController; - } - @Override protected Object doExecute() throws Exception { CamelContext camel = camelController.getCamelContext(context); diff --git a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/BacklogTracerStart.java b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/BacklogTracerStart.java index f77225dd6b185..4f880916950ea 100644 --- a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/BacklogTracerStart.java +++ b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/BacklogTracerStart.java @@ -21,13 +21,12 @@ import org.apache.felix.gogo.commands.Argument; import org.apache.felix.gogo.commands.Command; import org.apache.felix.gogo.commands.Option; -import org.apache.karaf.shell.console.OsgiCommandSupport; /** * Command to use the Backlog Tracer. */ @Command(scope = "camel", name = "backlog-tracer-start", description = "Starts the Backlog tracer") -public class BacklogTracerStart extends OsgiCommandSupport { +public class BacklogTracerStart extends CamelCommandSupport { @Argument(index = 0, name = "context", description = "The name of the Camel context.", required = true, multiValued = false) @@ -49,12 +48,6 @@ public class BacklogTracerStart extends OsgiCommandSupport { required = false, multiValued = false) Boolean removeOnDump; - private CamelController camelController; - - public void setCamelController(CamelController camelController) { - this.camelController = camelController; - } - @Override protected Object doExecute() throws Exception { CamelContext camel = camelController.getCamelContext(context); diff --git a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/BacklogTracerStop.java b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/BacklogTracerStop.java index 402dabf36aad0..d1d9d76786ee5 100644 --- a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/BacklogTracerStop.java +++ b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/BacklogTracerStop.java @@ -20,23 +20,16 @@ import org.apache.camel.processor.interceptor.BacklogTracer; import org.apache.felix.gogo.commands.Argument; import org.apache.felix.gogo.commands.Command; -import org.apache.karaf.shell.console.OsgiCommandSupport; /** * Command to use the Backlog Tracer. */ @Command(scope = "camel", name = "backlog-tracer-stop", description = "Stops the Backlog tracer") -public class BacklogTracerStop extends OsgiCommandSupport { +public class BacklogTracerStop extends CamelCommandSupport { @Argument(index = 0, name = "context", description = "The name of the Camel context.", required = true, multiValued = false) String context; - private CamelController camelController; - - public void setCamelController(CamelController camelController) { - this.camelController = camelController; - } - @Override protected Object doExecute() throws Exception { CamelContext camel = camelController.getCamelContext(context); diff --git a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CamelCommandSupport.java b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CamelCommandSupport.java new file mode 100644 index 0000000000000..a1edfe27528a0 --- /dev/null +++ b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CamelCommandSupport.java @@ -0,0 +1,32 @@ +/** + * 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.karaf.commands; + +import org.apache.karaf.shell.console.OsgiCommandSupport; + +/** + * The abstract base class for karaf commands. + */ +public abstract class CamelCommandSupport extends OsgiCommandSupport { + + protected CamelController camelController; + + public void setCamelController(CamelController camelController) { + this.camelController = camelController; + } + +} diff --git a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CamelController.java b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CamelController.java index afc1abf4b7dde..b62a5f3d7bacb 100644 --- a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CamelController.java +++ b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CamelController.java @@ -19,6 +19,7 @@ import java.util.List; import org.apache.camel.CamelContext; +import org.apache.camel.Endpoint; import org.apache.camel.Route; import org.apache.camel.model.RouteDefinition; @@ -59,14 +60,6 @@ public interface CamelController { */ List getRoutes(String camelContextName, String filter); - /** - * Get all route definitions. If Camel context name is null, all route definitions from all contexts are listed. - * - * @param camelContextName the Camel context name. If null, all contexts are considered. - * @return the list of the Camel route definitions. - */ - List getRouteDefinitions(String camelContextName); - /** * Return the route with the given route ID. * @@ -85,4 +78,12 @@ public interface CamelController { */ RouteDefinition getRouteDefinition(String routeId, String camelContextName); -} + /** + * Return the endpoints + * + * @param camelContextName the Camel context. + * @return the endpoints + */ + List getEndpoints(String camelContextName); + +} \ No newline at end of file diff --git a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/ContextInfo.java b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/ContextInfo.java index 0cee886789e82..1fd1508475dc1 100644 --- a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/ContextInfo.java +++ b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/ContextInfo.java @@ -20,6 +20,7 @@ import java.util.Date; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Set; import javax.management.MBeanServer; import javax.management.ObjectName; @@ -30,7 +31,6 @@ import org.apache.camel.spi.ManagementAgent; import org.apache.felix.gogo.commands.Argument; import org.apache.felix.gogo.commands.Command; -import org.apache.karaf.shell.console.OsgiCommandSupport; import org.apache.karaf.util.StringEscapeUtils; import static org.apache.camel.util.UnitUtils.printUnitFromBytes; @@ -39,7 +39,7 @@ * Command to display detailed information about a Camel context. */ @Command(scope = "camel", name = "context-info", description = "Display detailed information about a Camel context.") -public class ContextInfo extends OsgiCommandSupport { +public class ContextInfo extends CamelCommandSupport { @Argument(index = 0, name = "name", description = "The name of the Camel context", required = true, multiValued = false) String name; @@ -47,12 +47,6 @@ public class ContextInfo extends OsgiCommandSupport { @Argument(index = 1, name = "mode", description = "Allows for different display modes (--verbose, etc)", required = false, multiValued = false) String mode; - private CamelController camelController; - - public void setCamelController(CamelController camelController) { - this.camelController = camelController; - } - public Object doExecute() throws Exception { CamelContext camelContext = camelController.getCamelContext(name); @@ -82,8 +76,8 @@ public Object doExecute() throws Exception { System.out.println(StringEscapeUtils.unescapeJava("\tTracing: " + camelContext.isTracing())); System.out.println(""); System.out.println(StringEscapeUtils.unescapeJava("\u001B[1mProperties\u001B[0m")); - for (String property : camelContext.getProperties().keySet()) { - System.out.println(StringEscapeUtils.unescapeJava("\t" + property + " = " + camelContext.getProperty(property))); + for (Map.Entry entry : camelContext.getProperties().entrySet()) { + System.out.println(StringEscapeUtils.unescapeJava("\t" + entry.getKey() + " = " + entry.getValue())); } System.out.println(""); @@ -100,8 +94,8 @@ public Object doExecute() throws Exception { System.out.println(""); System.out.println(StringEscapeUtils.unescapeJava("\u001B[1mDataformats\u001B[0m")); - for (String names : camelContext.getDataFormats().keySet()) { - System.out.println(StringEscapeUtils.unescapeJava("\t" + names)); + for (String name : camelContext.getDataFormats().keySet()) { + System.out.println(StringEscapeUtils.unescapeJava("\t" + name)); } System.out.println(""); diff --git a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/ContextList.java b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/ContextList.java index a7260b7b49ea0..ea6959802d6d0 100644 --- a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/ContextList.java +++ b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/ContextList.java @@ -23,30 +23,24 @@ import org.apache.camel.CamelContext; import org.apache.felix.gogo.commands.Command; -import org.apache.karaf.shell.console.OsgiCommandSupport; /** * List the Camel contexts available in the Karaf instance. */ @Command(scope = "camel", name = "context-list", description = "Lists all Camel contexts.") -public class ContextList extends OsgiCommandSupport { +public class ContextList extends CamelCommandSupport { - private static final String NAME_COLUMN_LABEL = "Name"; + private static final String CONTEXT_COLUMN_LABEL = "Context"; private static final String STATUS_COLUMN_LABEL = "Status"; private static final String UPTIME_COLUMN_LABEL = "Uptime"; private static final int DEFAULT_FORMAT_BUFFER_LENGTH = 24; - private static final String DEFAULT_FIELD_PREAMBLE = "[ "; - private static final String DEFAULT_FIELD_POSTAMBLE = " ]"; - private static final String DEFAULT_HEADER_PREAMBLE = " "; - private static final String DEFAULT_HEADER_POSTAMBLE = " "; + private static final String DEFAULT_FIELD_PREAMBLE = " "; + private static final String DEFAULT_FIELD_POSTAMBLE = " "; + private static final String DEFAULT_HEADER_PREAMBLE = " "; + private static final String DEFAULT_HEADER_POSTAMBLE = " "; private static final int DEFAULT_COLUMN_WIDTH_INCREMENT = 0; private static final int MAX_COLUMN_WIDTH = Integer.MAX_VALUE; - - private CamelController camelController; - - public void setCamelController(CamelController camelController) { - this.camelController = camelController; - } + private static final int MIN_COLUMN_WIDTH = 12; protected Object doExecute() throws Exception { final List camelContexts = camelController.getCamelContexts(); @@ -57,7 +51,8 @@ protected Object doExecute() throws Exception { final PrintStream out = System.out; if (camelContexts.size() > 0) { - out.println(String.format(headerFormat, NAME_COLUMN_LABEL, STATUS_COLUMN_LABEL, UPTIME_COLUMN_LABEL)); + out.println(String.format(headerFormat, CONTEXT_COLUMN_LABEL, STATUS_COLUMN_LABEL, UPTIME_COLUMN_LABEL)); + out.println(String.format(headerFormat, "-------", "------", "------")); for (final CamelContext camelContext : camelContexts) { out.println(String.format(rowFormat, camelContext.getName(), camelContext.getStatus(), camelContext.getUptime())); } @@ -86,7 +81,7 @@ private static Map computeColumnWidths(final Iterable retval = new Hashtable(3); - retval.put(NAME_COLUMN_LABEL, maxNameLen); + retval.put(CONTEXT_COLUMN_LABEL, maxNameLen); retval.put(STATUS_COLUMN_LABEL, maxStatusLen); retval.put(UPTIME_COLUMN_LABEL, maxUptimeLen); @@ -108,12 +103,15 @@ private static String buildFormatString(final Map columnWidths, } columnWidthIncrement = DEFAULT_COLUMN_WIDTH_INCREMENT; - final int nameLen = java.lang.Math.min(columnWidths.get(NAME_COLUMN_LABEL) + columnWidthIncrement, MAX_COLUMN_WIDTH); - final int statusLen = java.lang.Math.min(columnWidths.get(STATUS_COLUMN_LABEL) + columnWidthIncrement, MAX_COLUMN_WIDTH); - final int uptimeLen = java.lang.Math.min(columnWidths.get(UPTIME_COLUMN_LABEL) + columnWidthIncrement, MAX_COLUMN_WIDTH); + int contextLen = java.lang.Math.min(columnWidths.get(CONTEXT_COLUMN_LABEL) + columnWidthIncrement, MAX_COLUMN_WIDTH); + int statusLen = java.lang.Math.min(columnWidths.get(STATUS_COLUMN_LABEL) + columnWidthIncrement, MAX_COLUMN_WIDTH); + int uptimeLen = java.lang.Math.min(columnWidths.get(UPTIME_COLUMN_LABEL) + columnWidthIncrement, MAX_COLUMN_WIDTH); + contextLen = Math.max(MIN_COLUMN_WIDTH, contextLen); + statusLen = Math.max(MIN_COLUMN_WIDTH, statusLen); + // last row does not have min width final StringBuilder retval = new StringBuilder(DEFAULT_FORMAT_BUFFER_LENGTH); - retval.append(fieldPreamble).append("%-").append(nameLen).append('.').append(nameLen).append('s').append(fieldPostamble).append(' '); + retval.append(fieldPreamble).append("%-").append(contextLen).append('.').append(contextLen).append('s').append(fieldPostamble).append(' '); retval.append(fieldPreamble).append("%-").append(statusLen).append('.').append(statusLen).append('s').append(fieldPostamble).append(' '); retval.append(fieldPreamble).append("%-").append(uptimeLen).append('.').append(uptimeLen).append('s').append(fieldPostamble).append(' '); diff --git a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/ContextStart.java b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/ContextStart.java index b30fe0aa94fb7..229ccc6c760fd 100644 --- a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/ContextStart.java +++ b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/ContextStart.java @@ -19,23 +19,16 @@ import org.apache.camel.CamelContext; import org.apache.felix.gogo.commands.Argument; import org.apache.felix.gogo.commands.Command; -import org.apache.karaf.shell.console.OsgiCommandSupport; /** * Command to start a Camel context. */ @Command(scope = "camel", name = "context-start", description = "Start a Camel context.") -public class ContextStart extends OsgiCommandSupport { +public class ContextStart extends CamelCommandSupport { @Argument(index = 0, name = "context", description = "The name of the Camel context.", required = true, multiValued = false) String context; - private CamelController camelController; - - public void setCamelController(CamelController camelController) { - this.camelController = camelController; - } - public Object doExecute() throws Exception { CamelContext camelContext = camelController.getCamelContext(context); if (camelContext == null) { diff --git a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/ContextStop.java b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/ContextStop.java index 5cbd3309b53d1..7503602473c14 100644 --- a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/ContextStop.java +++ b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/ContextStop.java @@ -19,23 +19,16 @@ import org.apache.camel.CamelContext; import org.apache.felix.gogo.commands.Argument; import org.apache.felix.gogo.commands.Command; -import org.apache.karaf.shell.console.OsgiCommandSupport; /** * Command to stop a Camel context. */ @Command(scope = "camel", name = "context-stop", description = "Stop a Camel context.") -public class ContextStop extends OsgiCommandSupport { +public class ContextStop extends CamelCommandSupport { @Argument(index = 0, name = "context", description = "The name of the Camel context.", required = true, multiValued = false) String context; - private CamelController camelController; - - public void setCamelController(CamelController camelController) { - this.camelController = camelController; - } - public Object doExecute() throws Exception { CamelContext camelContext = camelController.getCamelContext(context); if (camelContext == null) { diff --git a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/EndpointList.java b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/EndpointList.java index 5cf39d35afb20..1056269088605 100644 --- a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/EndpointList.java +++ b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/EndpointList.java @@ -16,45 +16,152 @@ */ package org.apache.camel.karaf.commands; +import java.io.PrintStream; +import java.net.URLDecoder; +import java.util.Hashtable; import java.util.List; +import java.util.Map; -import org.apache.camel.CamelContext; import org.apache.camel.Endpoint; import org.apache.camel.ServiceStatus; import org.apache.camel.StatefulService; +import org.apache.camel.util.URISupport; +import org.apache.felix.gogo.commands.Argument; import org.apache.felix.gogo.commands.Command; -import org.apache.karaf.shell.console.OsgiCommandSupport; +import org.apache.felix.gogo.commands.Option; /** * List the Camel endpoints available in the Karaf instance. */ @Command(scope = "camel", name = "endpoint-list", description = "Lists all Camel endpoints available in CamelContexts.") -public class EndpointList extends OsgiCommandSupport { +public class EndpointList extends CamelCommandSupport { - protected static final String HEADER_FORMAT = "%-20s %-20s %-20s"; - protected static final String OUTPUT_FORMAT = "[%-18s] [%-18s] [%-18s]"; + private static final String CONTEXT_COLUMN_LABEL = "Context"; + private static final String URI_COLUMN_LABEL = "Uri"; + private static final String STATUS_COLUMN_LABEL = "Status"; - private CamelController camelController; + private static final int DEFAULT_COLUMN_WIDTH_INCREMENT = 0; + private static final String DEFAULT_FIELD_PREAMBLE = " "; + private static final String DEFAULT_FIELD_POSTAMBLE = " "; + private static final String DEFAULT_HEADER_PREAMBLE = " "; + private static final String DEFAULT_HEADER_POSTAMBLE = " "; + private static final int DEFAULT_FORMAT_BUFFER_LENGTH = 24; + // endpoint uris can be very long so clip by default after 120 chars + private static final int MAX_COLUMN_WIDTH = 120; + private static final int MIN_COLUMN_WIDTH = 12; - public void setCamelController(CamelController camelController) { - this.camelController = camelController; - } + @Argument(index = 0, name = "name", description = "The Camel context name where to look for the endpoints", required = false, multiValued = false) + String name; + + @Option(name = "--decode", aliases = "-d", description = "Whether to decode the endpoint uri so its human readable", + required = false, multiValued = false, valueToShowInHelp = "true") + Boolean decode; + + @Option(name = "--verbose", aliases = "-v", description = "Verbose output which does not limit the length of the uri shown", + required = false, multiValued = false, valueToShowInHelp = "false") + Boolean verbose; protected Object doExecute() throws Exception { - System.out.println(String.format(HEADER_FORMAT, "camel-id", "uri", "Status")); + List endpoints = camelController.getEndpoints(name); - List camelContexts = camelController.getCamelContexts(); - for (CamelContext camelContext : camelContexts) { - List endpoints = (List) camelContext.getEndpoints(); - for (Endpoint endpoint : endpoints) { - System.out.println(String.format(OUTPUT_FORMAT, camelContext.getName(), endpoint.getEndpointUri(), getState(endpoint))); + final Map columnWidths = computeColumnWidths(endpoints); + final String headerFormat = buildFormatString(columnWidths, true); + final String rowFormat = buildFormatString(columnWidths, false); + final PrintStream out = System.out; + + if (endpoints.size() > 0) { + out.println(String.format(headerFormat, CONTEXT_COLUMN_LABEL, URI_COLUMN_LABEL, STATUS_COLUMN_LABEL)); + out.println(String.format(headerFormat, "-------", "---", "------")); + for (final Endpoint endpoint : endpoints) { + String contextId = endpoint.getCamelContext().getName(); + String uri = endpoint.getEndpointUri(); + if (decode == null || decode) { + // decode uri so its more human readable + uri = URLDecoder.decode(uri, "UTF-8"); + } + // sanitize and mask uri so we dont see passwords + uri = URISupport.sanitizeUri(uri); + String state = getEndpointState(endpoint); + out.println(String.format(rowFormat, contextId, uri, state)); } } return null; } - protected String getState(Endpoint endpoint) { + private Map computeColumnWidths(final Iterable endpoints) throws Exception { + if (endpoints == null) { + throw new IllegalArgumentException("Unable to determine column widths from null Iterable"); + } else { + int maxContextLen = 0; + int maxUriLen = 0; + int maxStatusLen = 0; + + for (final Endpoint endpoint : endpoints) { + final String name = endpoint.getCamelContext().getName(); + maxContextLen = java.lang.Math.max(maxContextLen, name == null ? 0 : name.length()); + + String uri = endpoint.getEndpointUri(); + if (decode == null || decode) { + // decode uri so its more human readable + uri = URLDecoder.decode(uri, "UTF-8"); + } + // sanitize and mask uri so we dont see passwords + uri = URISupport.sanitizeUri(uri); + + maxUriLen = java.lang.Math.max(maxUriLen, uri == null ? 0 : uri.length()); + + final String status = getEndpointState(endpoint); + maxStatusLen = java.lang.Math.max(maxStatusLen, status == null ? 0 : status.length()); + } + + final Map retval = new Hashtable(3); + retval.put(CONTEXT_COLUMN_LABEL, maxContextLen); + retval.put(URI_COLUMN_LABEL, maxUriLen); + retval.put(STATUS_COLUMN_LABEL, maxStatusLen); + + return retval; + } + } + + private String buildFormatString(final Map columnWidths, final boolean isHeader) { + final String fieldPreamble; + final String fieldPostamble; + final int columnWidthIncrement; + + if (isHeader) { + fieldPreamble = DEFAULT_HEADER_PREAMBLE; + fieldPostamble = DEFAULT_HEADER_POSTAMBLE; + } else { + fieldPreamble = DEFAULT_FIELD_PREAMBLE; + fieldPostamble = DEFAULT_FIELD_POSTAMBLE; + } + columnWidthIncrement = DEFAULT_COLUMN_WIDTH_INCREMENT; + + int contextLen = java.lang.Math.min(columnWidths.get(CONTEXT_COLUMN_LABEL) + columnWidthIncrement, getMaxColumnWidth()); + int uriLen = java.lang.Math.min(columnWidths.get(URI_COLUMN_LABEL) + columnWidthIncrement, getMaxColumnWidth()); + int statusLen = java.lang.Math.min(columnWidths.get(STATUS_COLUMN_LABEL) + columnWidthIncrement, getMaxColumnWidth()); + contextLen = Math.max(MIN_COLUMN_WIDTH, contextLen); + uriLen = Math.max(MIN_COLUMN_WIDTH, uriLen); + // last row does not have min width + + final StringBuilder retval = new StringBuilder(DEFAULT_FORMAT_BUFFER_LENGTH); + retval.append(fieldPreamble).append("%-").append(contextLen).append('.').append(contextLen).append('s').append(fieldPostamble).append(' '); + retval.append(fieldPreamble).append("%-").append(uriLen).append('.').append(uriLen).append('s').append(fieldPostamble).append(' '); + retval.append(fieldPreamble).append("%-").append(statusLen).append('.').append(statusLen).append('s').append(fieldPostamble).append(' '); + + return retval.toString(); + } + + private int getMaxColumnWidth() { + if (verbose != null && verbose) { + return Integer.MAX_VALUE; + } else { + return MAX_COLUMN_WIDTH; + } + } + + private static String getEndpointState(Endpoint endpoint) { // must use String type to be sure remote JMX can read the attribute without requiring Camel classes. if (endpoint instanceof StatefulService) { ServiceStatus status = ((StatefulService) endpoint).getStatus(); diff --git a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/RouteInfo.java b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/RouteInfo.java index 5391a40f48df8..5fdb214c99539 100644 --- a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/RouteInfo.java +++ b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/RouteInfo.java @@ -19,6 +19,7 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.Iterator; +import java.util.Map; import java.util.Set; import javax.management.MBeanServer; @@ -31,14 +32,13 @@ import org.apache.camel.spi.ManagementAgent; import org.apache.felix.gogo.commands.Argument; import org.apache.felix.gogo.commands.Command; -import org.apache.karaf.shell.console.OsgiCommandSupport; import org.apache.karaf.util.StringEscapeUtils; /** * Command to display detailed information about a Camel route. */ @Command(scope = "camel", name = "route-info", description = "Display information about a Camel route.") -public class RouteInfo extends OsgiCommandSupport { +public class RouteInfo extends CamelCommandSupport { @Argument(index = 0, name = "route", description = "The Camel route ID.", required = true, multiValued = false) String route; @@ -46,12 +46,6 @@ public class RouteInfo extends OsgiCommandSupport { @Argument(index = 1, name = "context", description = "The Camel context name.", required = false, multiValued = false) String context; - private CamelController camelController; - - public void setCamelController(CamelController camelController) { - this.camelController = camelController; - } - public Object doExecute() throws Exception { Route camelRoute = camelController.getRoute(route, context); @@ -64,8 +58,8 @@ public Object doExecute() throws Exception { System.out.println(StringEscapeUtils.unescapeJava("\tCamel Context: " + camelRoute.getRouteContext().getCamelContext().getName())); System.out.println(""); System.out.println(StringEscapeUtils.unescapeJava("\u001B[1mProperties\u001B[0m")); - for (String property : camelRoute.getProperties().keySet()) { - System.out.println(StringEscapeUtils.unescapeJava("\t\t" + property + " = " + camelRoute.getProperties().get(property))); + for (Map.Entry entry : camelRoute.getProperties().entrySet()) { + System.out.println(StringEscapeUtils.unescapeJava("\t" + entry.getKey() + " = " + entry.getValue())); } System.out.println(""); System.out.println(StringEscapeUtils.unescapeJava("\u001B[1mStatistics\u001B[0m")); diff --git a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/RouteList.java b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/RouteList.java index fcf7dc30410d9..b1e29883beedf 100644 --- a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/RouteList.java +++ b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/RouteList.java @@ -16,60 +16,115 @@ */ package org.apache.camel.karaf.commands; -import java.util.LinkedList; +import java.io.PrintStream; +import java.util.Hashtable; import java.util.List; +import java.util.Map; -import org.apache.camel.CamelContext; +import org.apache.camel.Route; import org.apache.camel.ServiceStatus; -import org.apache.camel.model.RouteDefinition; import org.apache.felix.gogo.commands.Argument; import org.apache.felix.gogo.commands.Command; -import org.apache.karaf.shell.console.OsgiCommandSupport; /** * Command to list all Camel routes. */ @Command(scope = "camel", name = "route-list", description = "List Camel routes.") -public class RouteList extends OsgiCommandSupport { +public class RouteList extends CamelCommandSupport { - protected static final String HEADER_FORMAT = "%-20s %-20s %-20s"; - protected static final String OUTPUT_FORMAT = "[%-18s] [%-18s] [%-18s]"; - protected static final String UNKNOWN = "Unknown"; - protected static final String ROUTE_ID = "Route Id"; - protected static final String CONTEXT_ID = "Context Name"; - protected static final String STATUS = "Status"; + private static final String CONTEXT_COLUMN_LABEL = "Context"; + private static final String ROUTE_COLUMN_LABEL = "Route"; + private static final String STATUS_COLUMN_LABEL = "Status"; + + private static final int DEFAULT_COLUMN_WIDTH_INCREMENT = 0; + private static final String DEFAULT_FIELD_PREAMBLE = " "; + private static final String DEFAULT_FIELD_POSTAMBLE = " "; + private static final String DEFAULT_HEADER_PREAMBLE = " "; + private static final String DEFAULT_HEADER_POSTAMBLE = " "; + private static final int DEFAULT_FORMAT_BUFFER_LENGTH = 24; + private static final int MAX_COLUMN_WIDTH = Integer.MAX_VALUE; + private static final int MIN_COLUMN_WIDTH = 12; @Argument(index = 0, name = "name", description = "The Camel context name where to look for the route", required = false, multiValued = false) String name; - private CamelController camelController; + protected Object doExecute() throws Exception { + List routes = camelController.getRoutes(name); - public void setCamelController(CamelController camelController) { - this.camelController = camelController; - } + final Map columnWidths = computeColumnWidths(routes); + final String headerFormat = buildFormatString(columnWidths, true); + final String rowFormat = buildFormatString(columnWidths, false); + final PrintStream out = System.out; - protected Object doExecute() throws Exception { - System.out.println(String.format(HEADER_FORMAT, ROUTE_ID, CONTEXT_ID, STATUS)); + if (routes.size() > 0) { + out.println(String.format(headerFormat, CONTEXT_COLUMN_LABEL, ROUTE_COLUMN_LABEL, STATUS_COLUMN_LABEL)); + out.println(String.format(headerFormat, "-------", "-----", "------")); + for (Route route : routes) { + String contextId = route.getRouteContext().getCamelContext().getName(); + String routeId = route.getId(); + ServiceStatus status = route.getRouteContext().getCamelContext().getRouteStatus(routeId); + out.println(String.format(rowFormat, contextId, routeId, status)); + } + } - List camelContexts = new LinkedList(); - if (name != null && camelController.getCamelContext(name) != null) { - camelContexts.add(camelController.getCamelContext(name)); + return null; + } + + private static Map computeColumnWidths(final Iterable routes) throws Exception { + if (routes == null) { + throw new IllegalArgumentException("Unable to determine column widths from null Iterable"); } else { - camelContexts = camelController.getCamelContexts(); - } + int maxContextLen = 0; + int maxRouteLen = 0; + int maxStatusLen = 0; + + for (final Route route : routes) { + final String contextId = route.getRouteContext().getCamelContext().getName(); + maxContextLen = java.lang.Math.max(maxContextLen, contextId == null ? 0 : contextId.length()); - for (CamelContext camelContext : camelContexts) { - List routeDefinitions = camelController.getRouteDefinitions(camelContext.getName()); - if (routeDefinitions != null && !routeDefinitions.isEmpty()) { - for (RouteDefinition routeDefinition : routeDefinitions) { - String contextName = camelContext.getName(); - ServiceStatus status = camelContext.getRouteStatus(routeDefinition.getId()); - System.out.println(String.format(OUTPUT_FORMAT, routeDefinition.getId(), contextName, status != null ? status.name() : UNKNOWN)); - } + final String routeId = route.getId(); + maxRouteLen = java.lang.Math.max(maxRouteLen, routeId == null ? 0 : routeId.length()); + + final String status = route.getRouteContext().getCamelContext().getRouteStatus(routeId).name(); + maxStatusLen = java.lang.Math.max(maxStatusLen, status == null ? 0 : status.length()); } + + final Map retval = new Hashtable(3); + retval.put(CONTEXT_COLUMN_LABEL, maxContextLen); + retval.put(ROUTE_COLUMN_LABEL, maxRouteLen); + retval.put(STATUS_COLUMN_LABEL, maxStatusLen); + + return retval; } + } - return null; + private static String buildFormatString(final Map columnWidths, final boolean isHeader) { + final String fieldPreamble; + final String fieldPostamble; + final int columnWidthIncrement; + + if (isHeader) { + fieldPreamble = DEFAULT_HEADER_PREAMBLE; + fieldPostamble = DEFAULT_HEADER_POSTAMBLE; + } else { + fieldPreamble = DEFAULT_FIELD_PREAMBLE; + fieldPostamble = DEFAULT_FIELD_POSTAMBLE; + } + columnWidthIncrement = DEFAULT_COLUMN_WIDTH_INCREMENT; + + int contextLen = Math.min(columnWidths.get(CONTEXT_COLUMN_LABEL) + columnWidthIncrement, MAX_COLUMN_WIDTH); + int routeLen = Math.min(columnWidths.get(ROUTE_COLUMN_LABEL) + columnWidthIncrement, MAX_COLUMN_WIDTH); + int statusLen = Math.min(columnWidths.get(STATUS_COLUMN_LABEL) + columnWidthIncrement, MAX_COLUMN_WIDTH); + contextLen = Math.max(MIN_COLUMN_WIDTH, contextLen); + routeLen = Math.max(MIN_COLUMN_WIDTH, routeLen); + // last row does not have min width + + final StringBuilder retval = new StringBuilder(DEFAULT_FORMAT_BUFFER_LENGTH); + retval.append(fieldPreamble).append("%-").append(contextLen).append('.').append(contextLen).append('s').append(fieldPostamble).append(' '); + retval.append(fieldPreamble).append("%-").append(routeLen).append('.').append(routeLen).append('s').append(fieldPostamble).append(' '); + retval.append(fieldPreamble).append("%-").append(statusLen).append('.').append(statusLen).append('s').append(fieldPostamble).append(' '); + + return retval.toString(); } } diff --git a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/RouteProfile.java b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/RouteProfile.java index c82f81237e369..98c94e4b7708f 100644 --- a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/RouteProfile.java +++ b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/RouteProfile.java @@ -38,7 +38,7 @@ public class RouteProfile extends AbstractRouteCommand { protected static final String HEADER_FORMAT = "%-30s %10s %12s %12s %12s %12s %12s %12s %12s"; - protected static final String OUTPUT_FORMAT = "[%-28s] [%8d] [%10d] [%10d] [%10d] [%10d] [%10d] [%10d] [%10d]"; + protected static final String OUTPUT_FORMAT = "%-30s %10d %12d %12d %12d %12d %12d %12d %12d"; private String previousCamelContextName; @@ -60,8 +60,6 @@ public void executeOnRoute(CamelContext camelContext, Route camelRoute) throws E System.out.println(StringEscapeUtils.unescapeJava("\tCamel Context: " + camelRoute.getRouteContext().getCamelContext().getName())); System.out.println(String.format(HEADER_FORMAT, "Id", "Count", "Last (ms)", "Delta (ms)", "Mean (ms)", "Min (ms)", "Max (ms)", "Total (ms)", "Self (ms)")); } -// System.out.println(StringEscapeUtils.unescapeJava("\u001B[1m\u001B[33mCamel Route " + camelRoute.getId() + "\u001B[0m")); -// System.out.println(StringEscapeUtils.unescapeJava("\tEndpoint uri: " + URISupport.sanitizeUri(camelRoute.getEndpoint().getEndpointUri()))); ManagementAgent agent = camelContext.getManagementStrategy().getManagementAgent(); if (agent != null) { diff --git a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/RouteShow.java b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/RouteShow.java index 31f4b2eb06113..87a71fab621e9 100644 --- a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/RouteShow.java +++ b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/RouteShow.java @@ -21,13 +21,12 @@ import org.apache.camel.model.RouteDefinition; import org.apache.felix.gogo.commands.Argument; import org.apache.felix.gogo.commands.Command; -import org.apache.karaf.shell.console.OsgiCommandSupport; /** * Command to show the route marshaled in XML. */ @Command(scope = "camel", name = "route-show", description = "Display the Camel route definition in XML.") -public class RouteShow extends OsgiCommandSupport { +public class RouteShow extends CamelCommandSupport { @Argument(index = 0, name = "route", description = "The Camel route ID.", required = true, multiValued = false) String route; @@ -35,12 +34,6 @@ public class RouteShow extends OsgiCommandSupport { @Argument(index = 1, name = "context", description = "The Camel context name.", required = false, multiValued = false) String context; - private CamelController camelController; - - public void setCamelController(CamelController camelController) { - this.camelController = camelController; - } - public Object doExecute() throws Exception { Route camelRoute = camelController.getRoute(route, context); if (camelRoute == null) { diff --git a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/completers/CamelCompleterSupport.java b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/completers/CamelCompleterSupport.java new file mode 100644 index 0000000000000..ff17d94637508 --- /dev/null +++ b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/completers/CamelCompleterSupport.java @@ -0,0 +1,34 @@ +/** + * 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.karaf.commands.completers; + +import org.apache.camel.karaf.commands.CamelController; + +import org.apache.karaf.shell.console.Completer; + +/** + * The abstract base class for completers. + */ +public abstract class CamelCompleterSupport implements Completer { + + protected CamelController camelController; + + public void setCamelController(CamelController camelController) { + this.camelController = camelController; + } + +} diff --git a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/completers/CamelContextCompleter.java b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/completers/CamelContextCompleter.java index 7026e0bab892c..54ced21244d55 100644 --- a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/completers/CamelContextCompleter.java +++ b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/completers/CamelContextCompleter.java @@ -20,19 +20,11 @@ import jline.console.completer.StringsCompleter; import org.apache.camel.CamelContext; -import org.apache.camel.karaf.commands.CamelController; -import org.apache.karaf.shell.console.Completer; /** * A JLine completer for the Camel contexts. */ -public class CamelContextCompleter implements Completer { - - private CamelController camelController; - - public void setCamelController(CamelController camelController) { - this.camelController = camelController; - } +public class CamelContextCompleter extends CamelCompleterSupport { @SuppressWarnings({"unchecked", "rawtypes"}) public int complete(String buffer, int cursor, List candidates) { diff --git a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/completers/RouteCompleter.java b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/completers/RouteCompleter.java index 92f04ad70e1c7..53a3d4d49f9b1 100644 --- a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/completers/RouteCompleter.java +++ b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/completers/RouteCompleter.java @@ -20,19 +20,11 @@ import jline.console.completer.StringsCompleter; import org.apache.camel.Route; -import org.apache.camel.karaf.commands.CamelController; -import org.apache.karaf.shell.console.Completer; /** * A Jline completer for the Camel routes. */ -public class RouteCompleter implements Completer { - - private CamelController camelController; - - public void setCamelController(CamelController camelController) { - this.camelController = camelController; - } +public class RouteCompleter extends CamelCompleterSupport { @SuppressWarnings({"unchecked", "rawtypes"}) public int complete(String buffer, int cursor, List candidates) { diff --git a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/internal/CamelControllerImpl.java b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/internal/CamelControllerImpl.java index 5cead101ff951..2bf1451ae3481 100644 --- a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/internal/CamelControllerImpl.java +++ b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/internal/CamelControllerImpl.java @@ -17,9 +17,12 @@ package org.apache.camel.karaf.commands.internal; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.List; import org.apache.camel.CamelContext; +import org.apache.camel.Endpoint; import org.apache.camel.Route; import org.apache.camel.karaf.commands.CamelController; import org.apache.camel.model.RouteDefinition; @@ -58,6 +61,15 @@ public List getCamelContexts() { } catch (Exception e) { LOG.warn("Cannot retrieve the list of Camel contexts.", e); } + + // sort the list + Collections.sort(camelContexts, new Comparator() { + @Override + public int compare(CamelContext o1, CamelContext o2) { + return o1.getName().compareTo(o2.getName()); + } + }); + return camelContexts; } @@ -71,34 +83,17 @@ public CamelContext getCamelContext(String name) { } public List getRoutes(String camelContextName) { - if (camelContextName != null) { - CamelContext context = this.getCamelContext(camelContextName); - if (context != null) { - return context.getRoutes(); - } - } else { - List routes = new ArrayList(); - List camelContexts = this.getCamelContexts(); - for (CamelContext camelContext : camelContexts) { - for (Route route : camelContext.getRoutes()) { - routes.add(route); - } - } - return routes; - } - return null; + return getRoutes(camelContextName, null); } public List getRoutes(String camelContextName, String filter) { - List routes = null; + List routes = new ArrayList(); + if (camelContextName != null) { CamelContext context = this.getCamelContext(camelContextName); if (context != null) { for (Route route : context.getRoutes()) { - if (routes == null) { - routes = new ArrayList(); - } - if (route.getId().matches(filter)) { + if (filter == null || route.getId().matches(filter)) { routes.add(route); } } @@ -107,36 +102,30 @@ public List getRoutes(String camelContextName, String filter) { List camelContexts = this.getCamelContexts(); for (CamelContext camelContext : camelContexts) { for (Route route : camelContext.getRoutes()) { - if (routes == null) { - routes = new ArrayList(); - } - if (route.getId().matches(filter)) { + if (filter == null || route.getId().matches(filter)) { routes.add(route); } } } } - return routes; - } - @SuppressWarnings("deprecation") - public List getRouteDefinitions(String camelContextName) { - if (camelContextName != null) { - CamelContext context = this.getCamelContext(camelContextName); - if (context != null) { - return context.getRouteDefinitions(); - } - } else { - List routeDefinitions = new ArrayList(); - List camelContexts = this.getCamelContexts(); - for (CamelContext camelContext : camelContexts) { - for (RouteDefinition routeDefinition : camelContext.getRouteDefinitions()) { - routeDefinitions.add(routeDefinition); + // sort the list + Collections.sort(routes, new Comparator() { + @Override + public int compare(Route o1, Route o2) { + // group by camel context first, then by route name + String c1 = o1.getRouteContext().getCamelContext().getName(); + String c2 = o2.getRouteContext().getCamelContext().getName(); + + int answer = c1.compareTo(c2); + if (answer == 0) { + // okay from same camel context, then sort by route id + answer = o1.getId().compareTo(o2.getId()); } + return answer; } - return routeDefinitions; - } - return null; + }); + return routes; } public Route getRoute(String routeId, String camelContextName) { @@ -158,4 +147,38 @@ public RouteDefinition getRouteDefinition(String routeId, String camelContextNam return context.getRouteDefinition(routeId); } + public List getEndpoints(String camelContextName) { + List answer = new ArrayList(); + + if (camelContextName != null) { + CamelContext context = this.getCamelContext(camelContextName); + if (context != null) { + List endpoints = new ArrayList(context.getEndpoints()); + // sort routes + Collections.sort(endpoints, new Comparator() { + @Override + public int compare(Endpoint o1, Endpoint o2) { + return o1.getEndpointKey().compareTo(o2.getEndpointKey()); + } + }); + answer.addAll(endpoints); + } + } else { + // already sorted by camel context + List camelContexts = this.getCamelContexts(); + for (CamelContext camelContext : camelContexts) { + List endpoints = new ArrayList(camelContext.getEndpoints()); + // sort routes + Collections.sort(endpoints, new Comparator() { + @Override + public int compare(Endpoint o1, Endpoint o2) { + return o1.getEndpointKey().compareTo(o2.getEndpointKey()); + } + }); + answer.addAll(endpoints); + } + } + // already sorted + return answer; + } }