You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2019/08/13 06:25:03 UTC
[camel] 01/09: CAMEL-13850: Optimize model classes to provide
changeable properties that support property placeholders to avoid
reflection. Work in progress.
This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch CAMEL-13850
in repository https://gitbox.apache.org/repos/asf/camel.git
commit b7071c82f4ff06dd19779ee295dcf00964fc97ae
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon Aug 12 07:18:47 2019 +0200
CAMEL-13850: Optimize model classes to provide changeable properties that support property placeholders to avoid reflection. Work in progress.
---
.../org/apache/camel/model/FromDefinition.java | 26 ++++-
.../java/org/apache/camel/model/LogDefinition.java | 31 +++++-
.../camel/model/ProcessorDefinitionHelper.java | 111 ++++++++++-----------
.../camel/model/PropertyPlaceholderAware.java | 38 +++++++
.../java/org/apache/camel/model/ToDefinition.java | 56 ++++++++++-
...ockTest.java => SimpleMockPlaceholderTest.java} | 23 ++++-
.../org/apache/camel/processor/SimpleMockTest.java | 2 -
.../camel/support/PropertyPlaceholdersHelper.java | 2 +
8 files changed, 221 insertions(+), 68 deletions(-)
diff --git a/core/camel-core/src/main/java/org/apache/camel/model/FromDefinition.java b/core/camel-core/src/main/java/org/apache/camel/model/FromDefinition.java
index e1faba2..6d61c6d 100644
--- a/core/camel-core/src/main/java/org/apache/camel/model/FromDefinition.java
+++ b/core/camel-core/src/main/java/org/apache/camel/model/FromDefinition.java
@@ -16,12 +16,17 @@
*/
package org.apache.camel.model;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
+import org.apache.camel.CamelContext;
import org.apache.camel.Endpoint;
import org.apache.camel.builder.EndpointConsumerBuilder;
import org.apache.camel.spi.Metadata;
@@ -32,7 +37,7 @@ import org.apache.camel.spi.Metadata;
@Metadata(label = "eip,endpoint,routing")
@XmlRootElement(name = "from")
@XmlAccessorType(XmlAccessType.FIELD)
-public class FromDefinition extends OptionalIdentifiedDefinition<FromDefinition> implements EndpointRequiredDefinition {
+public class FromDefinition extends OptionalIdentifiedDefinition<FromDefinition> implements PropertyPlaceholderAware, EndpointRequiredDefinition {
@XmlAttribute @Metadata(required = true)
private String uri;
@XmlTransient
@@ -40,18 +45,28 @@ public class FromDefinition extends OptionalIdentifiedDefinition<FromDefinition>
@XmlTransient
private EndpointConsumerBuilder endpointConsumerBuilder;
+ private final Map<String, Supplier<String>> readPlaceholders = new HashMap<>();
+ private final Map<String, Consumer<String>> writePlaceholders = new HashMap<>();
+
public FromDefinition() {
+ readPlaceholders.put("id", this::getId);
+ readPlaceholders.put("uri", this::getUri);
+ writePlaceholders.put("id", this::setId);
+ writePlaceholders.put("uri", this::setUri);
}
public FromDefinition(String uri) {
+ this();
setUri(uri);
}
public FromDefinition(Endpoint endpoint) {
+ this();
setEndpoint(endpoint);
}
public FromDefinition(EndpointConsumerBuilder endpointConsumerBuilder) {
+ this();
setEndpointConsumerBuilder(endpointConsumerBuilder);
}
@@ -135,4 +150,13 @@ public class FromDefinition extends OptionalIdentifiedDefinition<FromDefinition>
this.uri = null;
}
+ @Override
+ public Map<String, Supplier<String>> getReadPropertyPlaceholderOptions(CamelContext camelContext) {
+ return readPlaceholders;
+ }
+
+ @Override
+ public Map<String, Consumer<String>> getWritePropertyPlaceholderOptions(CamelContext camelContext) {
+ return writePlaceholders;
+ }
}
diff --git a/core/camel-core/src/main/java/org/apache/camel/model/LogDefinition.java b/core/camel-core/src/main/java/org/apache/camel/model/LogDefinition.java
index c8e1b0a..62281e5 100644
--- a/core/camel-core/src/main/java/org/apache/camel/model/LogDefinition.java
+++ b/core/camel-core/src/main/java/org/apache/camel/model/LogDefinition.java
@@ -16,12 +16,17 @@
*/
package org.apache.camel.model;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
+import org.apache.camel.CamelContext;
import org.apache.camel.LoggingLevel;
import org.apache.camel.spi.Metadata;
import org.slf4j.Logger;
@@ -32,7 +37,7 @@ import org.slf4j.Logger;
@Metadata(label = "eip,configuration")
@XmlRootElement(name = "log")
@XmlAccessorType(XmlAccessType.FIELD)
-public class LogDefinition extends NoOutputDefinition<LogDefinition> {
+public class LogDefinition extends NoOutputDefinition<LogDefinition> implements PropertyPlaceholderAware {
@XmlAttribute(required = true)
private String message;
@@ -47,10 +52,24 @@ public class LogDefinition extends NoOutputDefinition<LogDefinition> {
@XmlTransient
private Logger logger;
+ private final Map<String, Supplier<String>> readPlaceholders = new HashMap<>();
+ private final Map<String, Consumer<String>> writePlaceholders = new HashMap<>();
+
public LogDefinition() {
+ readPlaceholders.put("id", this::getId);
+ readPlaceholders.put("message", this::getMessage);
+ readPlaceholders.put("logName", this::getLogName);
+ readPlaceholders.put("marker", this::getMarker);
+ readPlaceholders.put("loggerRef", this::getLoggerRef);
+ writePlaceholders.put("id", this::setId);
+ writePlaceholders.put("message", this::setMessage);
+ writePlaceholders.put("logName", this::setLogName);
+ writePlaceholders.put("marker", this::setMarker);
+ writePlaceholders.put("loggerRef", this::setLoggerRef);
}
public LogDefinition(String message) {
+ this();
this.message = message;
}
@@ -136,4 +155,14 @@ public class LogDefinition extends NoOutputDefinition<LogDefinition> {
public void setLogger(Logger logger) {
this.logger = logger;
}
+
+ @Override
+ public Map<String, Supplier<String>> getReadPropertyPlaceholderOptions(CamelContext camelContext) {
+ return readPlaceholders;
+ }
+
+ @Override
+ public Map<String, Consumer<String>> getWritePropertyPlaceholderOptions(CamelContext camelContext) {
+ return writePlaceholders;
+ }
}
diff --git a/core/camel-core/src/main/java/org/apache/camel/model/ProcessorDefinitionHelper.java b/core/camel-core/src/main/java/org/apache/camel/model/ProcessorDefinitionHelper.java
index 420a7af..280965b 100644
--- a/core/camel-core/src/main/java/org/apache/camel/model/ProcessorDefinitionHelper.java
+++ b/core/camel-core/src/main/java/org/apache/camel/model/ProcessorDefinitionHelper.java
@@ -22,9 +22,12 @@ import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
import javax.xml.namespace.QName;
import org.apache.camel.CamelContext;
@@ -628,10 +631,31 @@ public final class ProcessorDefinitionHelper {
return rc;
}
- private static void addRestoreAction(final Object target, final Map<String, Object> properties) {
- addRestoreAction(null, target, properties);
+ private static void addRestoreAction(Map<String, Consumer<String>> writeProperties, final Map<String, String> properties) {
+ if (properties.isEmpty()) {
+ return;
+ }
+
+ RestoreAction restoreAction = CURRENT_RESTORE_ACTION.get();
+ if (restoreAction == null) {
+ return;
+ }
+
+ restoreAction.actions.add(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ properties.forEach((k, v) -> {
+ writeProperties.get(k).accept(v);
+ });
+ } catch (Exception e) {
+ LOG.warn("Cannot restore definition properties. This exception is ignored.", e);
+ }
+ }
+ });
}
-
+
+ @Deprecated
private static void addRestoreAction(final CamelContext context, final Object target, final Map<String, Object> properties) {
if (properties.isEmpty()) {
return;
@@ -681,70 +705,37 @@ public final class ProcessorDefinitionHelper {
public static void resolvePropertyPlaceholders(CamelContext camelContext, Object definition) throws Exception {
LOG.trace("Resolving property placeholders for: {}", definition);
+ // only do this for models that supports property placeholders
+ if (!(definition instanceof PropertyPlaceholderAware)) {
+ return;
+ }
+
+ PropertyPlaceholderAware ppa = (PropertyPlaceholderAware) definition;
+
// find all getter/setter which we can use for property placeholders
- Map<String, Object> properties = new HashMap<>();
- IntrospectionSupport.getProperties(definition, properties, null);
+ Map<String, String> changedProperties = new HashMap<>();
+ Map<String, Supplier<String>> readProperties = ppa.getReadPropertyPlaceholderOptions(camelContext);
+ Map<String, Consumer<String>> writeProperties = ppa.getWritePropertyPlaceholderOptions(camelContext);
- OtherAttributesAware other = null;
- if (definition instanceof OtherAttributesAware) {
- other = (OtherAttributesAware) definition;
- }
- // include additional properties which have the Camel placeholder QName
- // and when the definition parameter is this (otherAttributes belong to this)
- if (other != null && other.getOtherAttributes() != null) {
- for (QName key : other.getOtherAttributes().keySet()) {
- if (Constants.PLACEHOLDER_QNAME.equals(key.getNamespaceURI())) {
- String local = key.getLocalPart();
- Object value = other.getOtherAttributes().get(key);
- if (value instanceof String) {
- // enforce a properties component to be created if none existed
- camelContext.getPropertiesComponent(true);
-
- // value must be enclosed with placeholder tokens
- String s = (String) value;
- String prefixToken = PropertiesComponent.PREFIX_TOKEN;
- String suffixToken = PropertiesComponent.SUFFIX_TOKEN;
-
- if (!s.startsWith(prefixToken)) {
- s = prefixToken + s;
- }
- if (!s.endsWith(suffixToken)) {
- s = s + suffixToken;
- }
- value = s;
- }
- properties.put(local, value);
- }
+ if (!readProperties.isEmpty()) {
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("There are {} properties on: {}", readProperties.size(), definition);
}
- }
-
- Map<String, Object> changedProperties = new HashMap<>();
- if (!properties.isEmpty()) {
- LOG.trace("There are {} properties on: {}", properties.size(), definition);
// lookup and resolve properties for String based properties
- for (Map.Entry<String, Object> entry : properties.entrySet()) {
- // the name is always a String
+ for (Map.Entry<String, Supplier<String>> entry : readProperties.entrySet()) {
String name = entry.getKey();
- Object value = entry.getValue();
- if (value instanceof String) {
- // value must be a String, as a String is the key for a property placeholder
- String text = (String) value;
- text = camelContext.resolvePropertyPlaceholders(text);
- if (text != value) {
- // invoke setter as the text has changed
- boolean changed = IntrospectionSupport.setProperty(camelContext.getTypeConverter(), definition, name, text);
- if (!changed) {
- throw new IllegalArgumentException("No setter to set property: " + name + " to: " + text + " on: " + definition);
- }
- changedProperties.put(name, value);
- if (LOG.isDebugEnabled()) {
- LOG.debug("Changed property [{}] from: {} to: {}", name, value, text);
- }
+ String value = entry.getValue().get();
+ String text = camelContext.resolvePropertyPlaceholders(value);
+ if (!Objects.equals(text, value)) {
+ writeProperties.get(name).accept(text);
+ changedProperties.put(name, value);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Changed property [{}] from: {} to: {}", name, value, text);
}
}
}
}
- addRestoreAction(camelContext, definition, changedProperties);
+ addRestoreAction(writeProperties, changedProperties);
}
/**
@@ -758,7 +749,7 @@ public final class ProcessorDefinitionHelper {
*/
public static void resolveKnownConstantFields(CamelContext camelContext, Object definition) throws Exception {
LOG.trace("Resolving known fields for: {}", definition);
-
+/*
// find all String getter/setter
Map<String, Object> properties = new HashMap<>();
IntrospectionSupport.getProperties(definition, properties, null);
@@ -793,7 +784,7 @@ public final class ProcessorDefinitionHelper {
}
}
}
- addRestoreAction(definition, changedProperties);
+ addRestoreAction(camelContext, definition, changedProperties);*/
}
}
diff --git a/core/camel-core/src/main/java/org/apache/camel/model/PropertyPlaceholderAware.java b/core/camel-core/src/main/java/org/apache/camel/model/PropertyPlaceholderAware.java
new file mode 100644
index 0000000..9bc6b4a
--- /dev/null
+++ b/core/camel-core/src/main/java/org/apache/camel/model/PropertyPlaceholderAware.java
@@ -0,0 +1,38 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.model;
+
+import java.util.Map;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+import org.apache.camel.CamelContext;
+
+public interface PropertyPlaceholderAware {
+
+ /**
+ * Gets the options on the model definition which supports property placeholders and can be resolved.
+ *
+ * @return key/values of options
+ */
+ Map<String, Supplier<String>> getReadPropertyPlaceholderOptions(CamelContext camelContext);
+
+ /**
+ * To update an existing property using the function with the ket/value and returning the changed value
+ */
+ Map<String, Consumer<String>> getWritePropertyPlaceholderOptions(CamelContext camelContext);
+}
diff --git a/core/camel-core/src/main/java/org/apache/camel/model/ToDefinition.java b/core/camel-core/src/main/java/org/apache/camel/model/ToDefinition.java
index 78828ad..3a0ba35 100644
--- a/core/camel-core/src/main/java/org/apache/camel/model/ToDefinition.java
+++ b/core/camel-core/src/main/java/org/apache/camel/model/ToDefinition.java
@@ -16,15 +16,22 @@
*/
package org.apache.camel.model;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
+import org.apache.camel.CamelContext;
import org.apache.camel.Endpoint;
import org.apache.camel.ExchangePattern;
import org.apache.camel.builder.EndpointProducerBuilder;
import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.PropertiesComponent;
/**
* Sends the message to a static endpoint
@@ -32,22 +39,32 @@ import org.apache.camel.spi.Metadata;
@Metadata(label = "eip,endpoint,routing")
@XmlRootElement(name = "to")
@XmlAccessorType(XmlAccessType.FIELD)
-public class ToDefinition extends SendDefinition<ToDefinition> {
+public class ToDefinition extends SendDefinition<ToDefinition> implements PropertyPlaceholderAware {
@XmlAttribute
private ExchangePattern pattern;
+ private final Map<String, Supplier<String>> readPlaceholders = new HashMap<>();
+ private final Map<String, Consumer<String>> writePlaceholders = new HashMap<>();
+
public ToDefinition() {
+ readPlaceholders.put("id", this::getId);
+ readPlaceholders.put("uri", this::getUri);
+ writePlaceholders.put("id", this::setId);
+ writePlaceholders.put("uri", this::setUri);
}
public ToDefinition(String uri) {
+ this();
setUri(uri);
}
public ToDefinition(Endpoint endpoint) {
+ this();
setEndpoint(endpoint);
}
public ToDefinition(EndpointProducerBuilder endpointDefinition) {
+ this();
setEndpointProducerBuilder(endpointDefinition);
}
@@ -88,4 +105,41 @@ public class ToDefinition extends SendDefinition<ToDefinition> {
this.pattern = pattern;
}
+ @Override
+ public Map<String, Supplier<String>> getReadPropertyPlaceholderOptions(final CamelContext camelContext) {
+ if (getOtherAttributes() != null && !getOtherAttributes().isEmpty()) {
+ final Map<String, Supplier<String>> answer = new HashMap<>(readPlaceholders);
+ getOtherAttributes().forEach((k, v) -> {
+ if (Constants.PLACEHOLDER_QNAME.equals(k.getNamespaceURI())) {
+ if (v instanceof String) {
+ // enforce a properties component to be created if none existed
+ camelContext.getPropertiesComponent(true);
+
+ // value must be enclosed with placeholder tokens
+ String s = (String) v;
+ String prefixToken = PropertiesComponent.PREFIX_TOKEN;
+ String suffixToken = PropertiesComponent.SUFFIX_TOKEN;
+
+ if (!s.startsWith(prefixToken)) {
+ s = prefixToken + s;
+ }
+ if (!s.endsWith(suffixToken)) {
+ s = s + suffixToken;
+ }
+ final String value = s;
+ answer.put(k.getLocalPart(), () -> value);
+ }
+ }
+ });
+ return answer;
+ } else {
+ return readPlaceholders;
+ }
+ }
+
+ @Override
+ public Map<String, Consumer<String>> getWritePropertyPlaceholderOptions(CamelContext camelContext) {
+ return writePlaceholders;
+ }
}
+
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/SimpleMockTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/SimpleMockPlaceholderTest.java
similarity index 71%
copy from core/camel-core/src/test/java/org/apache/camel/processor/SimpleMockTest.java
copy to core/camel-core/src/test/java/org/apache/camel/processor/SimpleMockPlaceholderTest.java
index b8bd72d..dd8b986 100644
--- a/core/camel-core/src/test/java/org/apache/camel/processor/SimpleMockTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/SimpleMockPlaceholderTest.java
@@ -16,14 +16,31 @@
*/
package org.apache.camel.processor;
-import java.util.stream.Stream;
+import java.util.Properties;
+import org.apache.camel.CamelContext;
import org.apache.camel.ContextTestSupport;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.component.properties.PropertiesComponent;
import org.junit.Test;
-public class SimpleMockTest extends ContextTestSupport {
+public class SimpleMockPlaceholderTest extends ContextTestSupport {
+
+ @Override
+ protected CamelContext createCamelContext() throws Exception {
+ CamelContext context = super.createCamelContext();
+
+ Properties myProp = new Properties();
+ myProp.put("foo", "log:foo");
+ myProp.put("end", "result");
+
+ PropertiesComponent pc = new PropertiesComponent();
+ pc.setInitialProperties(myProp);
+ context.addComponent("properties", pc);
+
+ return context;
+ }
@Test
public void testSimple() throws Exception {
@@ -51,7 +68,7 @@ public class SimpleMockTest extends ContextTestSupport {
return new RouteBuilder() {
@Override
public void configure() throws Exception {
- from("direct:start").to("log:foo").to("log:bar").to("mock:result");
+ from("direct:start").to("{{foo}}").to("log:bar").to("mock:{{end}}");
}
};
}
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/SimpleMockTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/SimpleMockTest.java
index b8bd72d..015a692 100644
--- a/core/camel-core/src/test/java/org/apache/camel/processor/SimpleMockTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/SimpleMockTest.java
@@ -16,8 +16,6 @@
*/
package org.apache.camel.processor;
-import java.util.stream.Stream;
-
import org.apache.camel.ContextTestSupport;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.mock.MockEndpoint;
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/PropertyPlaceholdersHelper.java b/core/camel-support/src/main/java/org/apache/camel/support/PropertyPlaceholdersHelper.java
index c895914..84e44e9 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/PropertyPlaceholdersHelper.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/PropertyPlaceholdersHelper.java
@@ -45,6 +45,8 @@ public final class PropertyPlaceholdersHelper {
public static void resolvePropertyPlaceholders(CamelContext camelContext, Object object) throws Exception {
LOG.trace("Resolving property placeholders for: {}", object);
+ // TODO: Like ProcessorDefinitionHelper we want to avoid reflection
+
// find all getter/setter which we can use for property placeholders
Map<String, Object> properties = new HashMap<>();
IntrospectionSupport.getProperties(object, properties, null);