CAMEL-10447 Add contract based type awareness and transformer which leverages the type metadata
Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/7ba090f5 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/7ba090f5 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/7ba090f5 Branch: refs/heads/master Commit: 7ba090f5ca58f2f4a040898e56db3e11ba24fcde Parents: b650414 Author: Tomohisa Igarashi <tm.igara...@gmail.com> Authored: Fri Jul 15 22:41:04 2016 +0900 Committer: Claus Ibsen <davscl...@apache.org> Committed: Thu Nov 24 10:45:13 2016 +0100 ---------------------------------------------------------------------- .../java/org/apache/camel/CamelContext.java | 34 ++ .../main/java/org/apache/camel/Exchange.java | 3 + .../apache/camel/impl/DefaultCamelContext.java | 61 ++++ .../apache/camel/impl/DefaultRouteContext.java | 11 + .../impl/transformer/DataFormatTransformer.java | 154 ++++++++ .../impl/transformer/ProcessorTransformer.java | 122 +++++++ .../camel/impl/transformer/TransformerKey.java | 75 ++++ .../java/org/apache/camel/model/Constants.java | 3 +- .../apache/camel/model/InputTypeDefinition.java | 79 +++++ .../camel/model/OutputTypeDefinition.java | 80 +++++ .../org/apache/camel/model/RouteDefinition.java | 80 ++++- .../CustomTransformerDefinition.java | 106 ++++++ .../DataFormatTransformerDefinition.java | 161 +++++++++ .../EndpointTransformerDefinition.java | 88 +++++ .../transformer/TransformerDefinition.java | 133 +++++++ .../transformer/TransformersDefinition.java | 58 +++ .../camel/model/transformer/package-info.java | 24 ++ .../camel/processor/CamelInternalProcessor.java | 120 +++++++ .../java/org/apache/camel/spi/Contract.java | 112 ++++++ .../java/org/apache/camel/spi/DataType.java | 89 +++++ .../java/org/apache/camel/spi/RouteContext.java | 5 + .../java/org/apache/camel/spi/Transformer.java | 128 +++++++ .../resources/org/apache/camel/model/jaxb.index | 2 + .../apache/camel/model/transformer/jaxb.index | 21 ++ .../transformer/TransformerContractTest.java | 173 +++++++++ .../impl/transformer/TransformerRouteTest.java | 349 +++++++++++++++++++ .../blueprint/CamelContextFactoryBean.java | 11 + .../camel/cdi/xml/CamelContextFactoryBean.java | 12 + .../xml/AbstractCamelContextFactoryBean.java | 6 + .../camel/spring/CamelContextFactoryBean.java | 14 + .../spring/handler/CamelNamespaceHandler.java | 1 + .../transformer/SpringTransformerRouteTest.java | 48 +++ .../transformer/SpringTransformerRouteTest.xml | 97 ++++++ examples/README.md | 5 + .../README.md | 51 +++ .../camel-example-transformer-blueprint/pom.xml | 121 +++++++ .../OSGI-INF/blueprint/camel-context.xml | 53 +++ .../src/main/resources/features.xml | 29 ++ .../src/main/resources/log4j2.properties | 28 ++ .../src/main/resources/transform.xsl | 14 + .../camel-example-transformer-cdi/README.md | 37 ++ examples/camel-example-transformer-cdi/pom.xml | 102 ++++++ .../camel/example/transformer/cdi/MyRoutes.java | 56 +++ .../src/main/resources/META-INF/LICENSE.txt | 203 +++++++++++ .../src/main/resources/META-INF/NOTICE.txt | 11 + .../src/main/resources/META-INF/beans.xml | 18 + .../src/main/resources/log4j2.properties | 28 ++ .../src/main/resources/transform.xsl | 14 + .../camel-example-transformer-demo/README.md | 33 ++ examples/camel-example-transformer-demo/pom.xml | 141 ++++++++ .../camel/example/transformer/demo/Order.java | 82 +++++ .../transformer/demo/OrderProcessor.java | 41 +++ .../example/transformer/demo/OrderResponse.java | 76 ++++ .../transformer/demo/client/CamelClient.java | 106 ++++++ .../src/main/resources/META-INF/LICENSE.txt | 203 +++++++++++ .../src/main/resources/META-INF/NOTICE.txt | 11 + .../resources/META-INF/spring/camel-context.xml | 100 ++++++ .../src/main/resources/features.xml | 30 ++ .../src/main/resources/log4j2.properties | 28 ++ .../camel/example/transformer/demo/jaxb.index | 2 + .../transformer/OrderRouteSpringTest.java | 140 ++++++++ examples/pom.xml | 3 + 62 files changed, 4224 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/CamelContext.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/CamelContext.java b/camel-core/src/main/java/org/apache/camel/CamelContext.java index e3710d8..8c687b2 100644 --- a/camel-core/src/main/java/org/apache/camel/CamelContext.java +++ b/camel-core/src/main/java/org/apache/camel/CamelContext.java @@ -36,11 +36,13 @@ import org.apache.camel.model.RoutesDefinition; import org.apache.camel.model.remote.ServiceCallConfigurationDefinition; import org.apache.camel.model.rest.RestDefinition; import org.apache.camel.model.rest.RestsDefinition; +import org.apache.camel.model.transformer.TransformerDefinition; import org.apache.camel.spi.AsyncProcessorAwaitManager; import org.apache.camel.spi.CamelContextNameStrategy; import org.apache.camel.spi.ClassResolver; import org.apache.camel.spi.DataFormat; import org.apache.camel.spi.DataFormatResolver; +import org.apache.camel.spi.DataType; import org.apache.camel.spi.Debugger; import org.apache.camel.spi.EndpointRegistry; import org.apache.camel.spi.EndpointStrategy; @@ -69,6 +71,7 @@ import org.apache.camel.spi.RuntimeEndpointRegistry; import org.apache.camel.spi.ServicePool; import org.apache.camel.spi.ShutdownStrategy; import org.apache.camel.spi.StreamCachingStrategy; +import org.apache.camel.spi.Transformer; import org.apache.camel.spi.TypeConverterRegistry; import org.apache.camel.spi.UnitOfWorkFactory; import org.apache.camel.spi.UuidGenerator; @@ -1217,6 +1220,37 @@ public interface CamelContext extends SuspendableService, RuntimeConfiguration { void setDataFormatResolver(DataFormatResolver dataFormatResolver); /** + * Sets the transformers that can be referenced in the routes. + * + * @param transformers the transformers + */ + void setTransformers(List<TransformerDefinition> transformers); + + /** + * Gets the transformers that can be referenced in the routes. + * + * @return the transformers available + */ + List<TransformerDefinition> getTransformers(); + + /** + * Resolve a transformer given a scheme + * + * @param model data model name. + * @return the resolved transformer, or <tt>null</tt> if not found + */ + Transformer resolveTransformer(String model); + + /** + * Resolve a transformer given from/to data type. + * + * @param from from data type + * @param to to data type + * @return the resolved data format, or <tt>null</tt> if not found + */ + Transformer resolveTransformer(DataType from, DataType to); + + /** * Sets the properties that can be referenced in the camel context * <p/> * <b>Important:</b> This has nothing to do with property placeholders, and is just a plain set of key/value pairs http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/Exchange.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/Exchange.java b/camel-core/src/main/java/org/apache/camel/Exchange.java index b23da1a..b6f6c37 100644 --- a/camel-core/src/main/java/org/apache/camel/Exchange.java +++ b/camel-core/src/main/java/org/apache/camel/Exchange.java @@ -231,6 +231,9 @@ public interface Exchange { String XSLT_FATAL_ERROR = "CamelXsltFatalError"; String XSLT_WARNING = "CamelXsltWarning"; + String INPUT_TYPE = "CamelInputType"; + String OUTPUT_TYPE = "CamelOutputType"; + /** * Returns the {@link ExchangePattern} (MEP) of this exchange. * http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java b/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java index 12295bf..9cd8e83 100644 --- a/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java +++ b/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java @@ -90,6 +90,7 @@ import org.apache.camel.component.properties.PropertiesComponent; import org.apache.camel.impl.converter.BaseTypeConverterRegistry; import org.apache.camel.impl.converter.DefaultTypeConverter; import org.apache.camel.impl.converter.LazyLoadingTypeConverter; +import org.apache.camel.impl.transformer.TransformerKey; import org.apache.camel.management.DefaultManagementMBeanAssembler; import org.apache.camel.management.DefaultManagementStrategy; import org.apache.camel.management.JmxSystemPropertyKeys; @@ -105,6 +106,7 @@ import org.apache.camel.model.RoutesDefinition; import org.apache.camel.model.remote.ServiceCallConfigurationDefinition; import org.apache.camel.model.rest.RestDefinition; import org.apache.camel.model.rest.RestsDefinition; +import org.apache.camel.model.transformer.TransformerDefinition; import org.apache.camel.processor.interceptor.BacklogDebugger; import org.apache.camel.processor.interceptor.BacklogTracer; import org.apache.camel.processor.interceptor.Debug; @@ -119,6 +121,7 @@ import org.apache.camel.spi.ComponentResolver; import org.apache.camel.spi.Container; import org.apache.camel.spi.DataFormat; import org.apache.camel.spi.DataFormatResolver; +import org.apache.camel.spi.DataType; import org.apache.camel.spi.Debugger; import org.apache.camel.spi.EndpointRegistry; import org.apache.camel.spi.EndpointStrategy; @@ -150,6 +153,7 @@ import org.apache.camel.spi.RuntimeEndpointRegistry; import org.apache.camel.spi.ServicePool; import org.apache.camel.spi.ShutdownStrategy; import org.apache.camel.spi.StreamCachingStrategy; +import org.apache.camel.spi.Transformer; import org.apache.camel.spi.TypeConverterRegistry; import org.apache.camel.spi.UnitOfWorkFactory; import org.apache.camel.spi.UuidGenerator; @@ -276,6 +280,8 @@ public class DefaultCamelContext extends ServiceSupport implements ModelCamelCon private final StopWatch stopWatch = new StopWatch(false); private Date startDate; private ModelJAXBContextFactory modelJAXBContextFactory; + private List<TransformerDefinition> transformers = new ArrayList<TransformerDefinition>(); + private Map<TransformerKey, Transformer> transformerRegistry = new HashMap<TransformerKey, Transformer>(); /** * Creates the {@link CamelContext} using {@link JndiRegistry} as registry, @@ -4323,6 +4329,61 @@ public class DefaultCamelContext extends ServiceSupport implements ModelCamelCon } } } + } + + @Override + public void setTransformers(List<TransformerDefinition> transformers) { + this.transformers = transformers; + } + + @Override + public List<TransformerDefinition> getTransformers() { + return transformers; + } + + @Override + public Transformer resolveTransformer(String scheme) { + if (scheme == null) { + return null; + } + return resolveTransformer(getTransformerKey(scheme)); + } + + @Override + public Transformer resolveTransformer(DataType from, DataType to) { + if (from == null || to == null) { + return null; + } + return resolveTransformer(getTransformerKey(from, to)); + } + + protected Transformer resolveTransformer(TransformerKey key) { + Transformer transformer = transformerRegistry.get(key); + if (transformer != null) { + return transformer; + } + for (TransformerDefinition def : getTransformers()) { + if (key.match(def)) { + try { + transformer = def.createTransformer(this); + transformer.setCamelContext(this); + addService(transformer); + } catch (Exception e) { + throw new RuntimeCamelException(e); + } + log.debug("Registering Transformer '{}'", transformer); + transformerRegistry.put(key, transformer); + return transformer; + } + } + return null; + } + + protected TransformerKey getTransformerKey(String scheme) { + return new TransformerKey(scheme); + } + protected TransformerKey getTransformerKey(DataType from, DataType to) { + return new TransformerKey(from, to); } } http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/impl/DefaultRouteContext.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/impl/DefaultRouteContext.java b/camel-core/src/main/java/org/apache/camel/impl/DefaultRouteContext.java index d18ccb7..8a2e7c1 100644 --- a/camel-core/src/main/java/org/apache/camel/impl/DefaultRouteContext.java +++ b/camel-core/src/main/java/org/apache/camel/impl/DefaultRouteContext.java @@ -36,6 +36,7 @@ import org.apache.camel.model.ProcessorDefinition; import org.apache.camel.model.RouteDefinition; import org.apache.camel.processor.CamelInternalProcessor; import org.apache.camel.processor.Pipeline; +import org.apache.camel.spi.Contract; import org.apache.camel.spi.InterceptStrategy; import org.apache.camel.spi.RouteContext; import org.apache.camel.spi.RoutePolicy; @@ -68,6 +69,7 @@ public class DefaultRouteContext implements RouteContext { private List<RoutePolicy> routePolicyList = new ArrayList<RoutePolicy>(); private ShutdownRoute shutdownRoute; private ShutdownRunningTask shutdownRunningTask; + private Contract contract; public DefaultRouteContext(CamelContext camelContext, RouteDefinition route, FromDefinition from, Collection<Route> routes) { this.camelContext = camelContext; @@ -191,6 +193,11 @@ public class DefaultRouteContext implements RouteContext { // wrap in route lifecycle internal.addAdvice(new CamelInternalProcessor.RouteLifecycleAdvice()); + // wrap in contract + if (contract != null) { + internal.addAdvice(new CamelInternalProcessor.ContractAdvice(contract)); + } + // and create the route that wraps the UoW Route edcr = new EventDrivenConsumerRoute(this, getEndpoint(), internal); edcr.getProperties().put(Route.ID_PROPERTY, routeId); @@ -400,4 +407,8 @@ public class DefaultRouteContext implements RouteContext { public List<RoutePolicy> getRoutePolicyList() { return routePolicyList; } + + public void setContract(Contract contract) { + this.contract = contract; + } } http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/impl/transformer/DataFormatTransformer.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/impl/transformer/DataFormatTransformer.java b/camel-core/src/main/java/org/apache/camel/impl/transformer/DataFormatTransformer.java new file mode 100644 index 0000000..9993807 --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/impl/transformer/DataFormatTransformer.java @@ -0,0 +1,154 @@ +/** + * 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.impl.transformer; + +import java.io.InputStream; +import java.io.OutputStream; + +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.apache.camel.converter.stream.OutputStreamBuilder; +import org.apache.camel.model.DataFormatDefinition; +import org.apache.camel.model.transformer.DataFormatTransformerDefinition; +import org.apache.camel.spi.DataFormat; +import org.apache.camel.spi.DataType; +import org.apache.camel.spi.Transformer; +import org.apache.camel.support.ServiceSupport; +import org.apache.camel.util.ServiceHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A <a href="http://camel.apache.org/transformer.html">Transformer</a> + * leverages DataFormat to perform transformation. + */ +public class DataFormatTransformer extends Transformer { + private static final Logger LOG = LoggerFactory.getLogger(DataFormatTransformer.class); + + private String dataFormatRef; + private DataFormatDefinition dataFormatType; + private DataFormat dataFormat; + private String transformerString; + + public DataFormatTransformer(CamelContext context) { + setCamelContext(context); + } + + /** + * Perform data transformation with specified from/to type using DataFormat. + * @param message message to apply transformation + * @param from 'from' data type + * @param to 'to' data type + */ + @Override + public void transform(Message message, DataType from, DataType to) throws Exception { + Exchange exchange = message.getExchange(); + CamelContext context = exchange.getContext(); + + // Unmarshaling into Java Object + if ((to == null || to.isJavaType()) && (from.equals(getFrom()) || from.getModel().equals(getModel()))) { + DataFormat dataFormat = getDataFormat(exchange); + LOG.debug("Unmarshaling with '{}'", dataFormat); + Object answer = dataFormat.unmarshal(exchange, message.getBody(InputStream.class)); + if (to != null && to.getName() != null) { + Class<?> toClass = context.getClassResolver().resolveClass(to.getName()); + if (!toClass.isAssignableFrom(answer.getClass())) { + LOG.debug("Converting to '{}'", toClass.getName()); + answer = context.getTypeConverter().mandatoryConvertTo(toClass, answer); + } + } + message.setBody(answer); + + // Marshaling from Java Object + } else if ((from == null || from.isJavaType()) && (to.equals(getTo()) || to.getModel().equals(getModel()))) { + Object input = message.getBody(); + if (from != null && from.getName() != null) { + Class<?> fromClass = context.getClassResolver().resolveClass(from.getName()); + if (!fromClass.isAssignableFrom(input.getClass())) { + LOG.debug("Converting to '{}'", fromClass.getName()); + input = context.getTypeConverter().mandatoryConvertTo(fromClass, input); + } + } + OutputStreamBuilder osb = OutputStreamBuilder.withExchange(exchange); + DataFormat dataFormat = getDataFormat(exchange); + LOG.debug("Marshaling with '{}'", dataFormat); + dataFormat.marshal(exchange, message.getBody(), osb); + message.setBody(osb.build()); + + } else { + throw new IllegalArgumentException("Unsupported transformation: from='" + from + ", to='" + to + "'"); + } + } + + /** + * A bit dirty hack to create DataFormat instance, as it requires a RouteContext anyway. + */ + private DataFormat getDataFormat(Exchange exchange) throws Exception { + if (this.dataFormat == null) { + this.dataFormat = DataFormatDefinition.getDataFormat( + exchange.getUnitOfWork().getRouteContext(), this.dataFormatType, this.dataFormatRef); + if (this.dataFormat != null && !getCamelContext().hasService(this.dataFormat)) { + getCamelContext().addService(this.dataFormat, false); + } + } + return this.dataFormat; + } + + /** + * Set DataFormat ref. + * @param ref DataFormat ref + * @return this DataFormatTransformer instance + */ + public DataFormatTransformer setDataFormatRef(String ref) { + this.dataFormatRef = ref; + this.transformerString = null; + return this; + } + + /** + * Set DataFormatDefinition. + * @param dataFormatType DataFormatDefinition + * @return this DataFormatTransformer instance + */ + public DataFormatTransformer setDataFormatType(DataFormatDefinition dataFormatType) { + this.dataFormatType = dataFormatType; + this.transformerString = null; + return this; + } + + @Override + public String toString() { + if (transformerString == null) { + transformerString = + String.format("DataFormatTransformer[scheme='%s', from='%s', to='%s', ref='%s', type='%s']", + getModel(), getFrom(), getTo(), dataFormatRef, dataFormatType); + } + return transformerString; + } + + @Override + public void doStart() throws Exception { + // no-op + } + + @Override + public void doStop() throws Exception { + ServiceHelper.stopService(this.dataFormat); + getCamelContext().removeService(this.dataFormat); + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/impl/transformer/ProcessorTransformer.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/impl/transformer/ProcessorTransformer.java b/camel-core/src/main/java/org/apache/camel/impl/transformer/ProcessorTransformer.java new file mode 100644 index 0000000..f7bc2d4 --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/impl/transformer/ProcessorTransformer.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.impl.transformer; + +import org.apache.camel.CamelContext; +import org.apache.camel.Endpoint; +import org.apache.camel.Exchange; +import org.apache.camel.ExchangePattern; +import org.apache.camel.Message; +import org.apache.camel.Processor; +import org.apache.camel.impl.DefaultExchange; +import org.apache.camel.model.transformer.EndpointTransformerDefinition; +import org.apache.camel.processor.SendProcessor; +import org.apache.camel.spi.DataType; +import org.apache.camel.spi.Transformer; +import org.apache.camel.support.ServiceSupport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A <a href="http://camel.apache.org/transformer.html">Transformer</a> + * leverages Processor to perform transformation. + */ +public class ProcessorTransformer extends Transformer { + private static final Logger LOG = LoggerFactory.getLogger(ProcessorTransformer.class); + + private Processor processor; + private String transformerString; + + public ProcessorTransformer(CamelContext context) { + setCamelContext(context); + } + + /** + * Perform data transformation with specified from/to type using Processor. + * @param message message to apply transformation + * @param from 'from' data type + * @param to 'to' data type + */ + @Override + public void transform(Message message, DataType from, DataType to) throws Exception { + Exchange exchange = message.getExchange(); + CamelContext context = exchange.getContext(); + if (from.isJavaType()) { + Object input = message.getBody(); + Class<?> fromClass = context.getClassResolver().resolveClass(from.getName()); + if (!fromClass.isAssignableFrom(input.getClass())) { + LOG.debug("Converting to '{}'", fromClass.getName()); + input = context.getTypeConverter().mandatoryConvertTo(fromClass, input); + message.setBody(input); + } + } + + LOG.debug("Sending to transform processor '{}'", processor); + DefaultExchange transformExchange = new DefaultExchange(exchange); + transformExchange.setIn(message); + transformExchange.setProperties(exchange.getProperties()); + processor.process(transformExchange); + Message answer = transformExchange.hasOut() ? transformExchange.getOut() : transformExchange.getIn(); + + if (to.isJavaType()) { + Object answerBody = answer.getBody(); + Class<?> toClass = context.getClassResolver().resolveClass(to.getName()); + if (!toClass.isAssignableFrom(answerBody.getClass())) { + LOG.debug("Converting to '{}'", toClass.getName()); + answerBody = context.getTypeConverter().mandatoryConvertTo(toClass, answerBody); + answer.setBody(answerBody); + } + } + + message.copyFrom(answer); + } + + /** + * Set Processor. + * @param processor Processor + * @return this ProcessorTransformer instance + */ + public ProcessorTransformer setProcessor(Processor processor) { + this.processor = processor; + this.transformerString = null; + return this; + } + + @Override + public String toString() { + if (transformerString == null) { + transformerString = + String.format("ProcessorTransformer[scheme='%s', from='%s', to='%s', processor='%s']", + getModel(), getFrom(), getTo(), processor); + } + return transformerString; + } + + @Override + protected void doStart() throws Exception { + if (this.processor instanceof ServiceSupport) { + ((ServiceSupport)this.processor).start(); + } + } + + @Override + protected void doStop() throws Exception { + if (this.processor instanceof ServiceSupport) { + ((ServiceSupport)this.processor).stop(); + } + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/impl/transformer/TransformerKey.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/impl/transformer/TransformerKey.java b/camel-core/src/main/java/org/apache/camel/impl/transformer/TransformerKey.java new file mode 100644 index 0000000..c5680ea --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/impl/transformer/TransformerKey.java @@ -0,0 +1,75 @@ +/** + * 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.impl.transformer; + +import org.apache.camel.impl.DefaultCamelContext; +import org.apache.camel.impl.DefaultEndpointRegistry; +import org.apache.camel.model.transformer.TransformerDefinition; +import org.apache.camel.spi.DataType; +import org.apache.camel.util.ObjectHelper; +import org.apache.camel.util.ValueHolder; + +/** + * Key used in Transformer registry in {@link DefaultCamelContext}, + * to ensure a consistent lookup. + */ +public final class TransformerKey extends ValueHolder<String> { + + private String scheme; + private DataType from; + private DataType to; + + public TransformerKey(String scheme) { + super(scheme); + this.scheme = scheme; + ObjectHelper.notEmpty(scheme, "scheme"); + } + + public TransformerKey(DataType from, DataType to) { + super(createKeyString(from, to)); + this.from = from; + this.to = to; + } + + private static String createKeyString(DataType from, DataType to) { + return from + "/" + to; + } + + /** + * Test if specified TransformerDefinition matches with data type represented by this key. + * @param def TransformerDefinition + * @return true if it matches, otherwise false + */ + public boolean match(TransformerDefinition def) { + if (scheme != null) { + return scheme.equals(def.getScheme()); + } + if (from == null) { + return to.toString().equals(def.getTo()); + } + if (to == null) { + return from.toString().equals(def.getFrom()); + } + return from.toString().equals(def.getFrom()) && to.toString().equals(def.getTo()); + } + + @Override + public String toString() { + return get(); + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/model/Constants.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/model/Constants.java b/camel-core/src/main/java/org/apache/camel/model/Constants.java index 9c72ac1..eaec06e 100644 --- a/camel-core/src/main/java/org/apache/camel/model/Constants.java +++ b/camel-core/src/main/java/org/apache/camel/model/Constants.java @@ -31,7 +31,8 @@ public final class Constants { + "org.apache.camel.model.language:" + "org.apache.camel.model.loadbalancer:" + "org.apache.camel.model.remote:" - + "org.apache.camel.model.rest"; + + "org.apache.camel.model.rest:" + + "org.apache.camel.model.transformer"; public static final String PLACEHOLDER_QNAME = "http://camel.apache.org/schema/placeholder"; http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/model/InputTypeDefinition.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/model/InputTypeDefinition.java b/camel-core/src/main/java/org/apache/camel/model/InputTypeDefinition.java new file mode 100644 index 0000000..782e041 --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/model/InputTypeDefinition.java @@ -0,0 +1,79 @@ +/** + * 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.model; + +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.spi.Metadata; + +/** + * Set data type of the input message. + */ +@Metadata(label = "configuration") +@XmlRootElement(name = "inputType") +@XmlAccessorType(XmlAccessType.FIELD) +public class InputTypeDefinition extends OptionalIdentifiedDefinition<InputTypeDefinition> { + @XmlAttribute(required = true) + private String urn; + @XmlTransient + private Class<?> clazz; + + public InputTypeDefinition() { + } + + /** + * Get input type URN. + * @return input type URN + */ + public String getUrn() { + if (clazz != null) { + return "java:" + clazz.getName(); + } + return urn; + } + + /** + * Set input type URN. + * @param urn input type URN + */ + public void setUrn(String urn) { + this.urn = urn; + } + + /** + * Set input type via Java Class. + * @param clazz Java Class + */ + public void setJavaClass(Class<?> clazz) { + this.clazz = clazz; + } + + @Override + public String toString() { + return "inputType[" + urn + "]"; + } + + @Override + public String getLabel() { + return "inputType[" + urn + "]"; + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/model/OutputTypeDefinition.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/model/OutputTypeDefinition.java b/camel-core/src/main/java/org/apache/camel/model/OutputTypeDefinition.java new file mode 100644 index 0000000..755874a --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/model/OutputTypeDefinition.java @@ -0,0 +1,80 @@ +/** + * 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.model; + +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.spi.Metadata; + +/** + * Sets data type of the output message. + */ +@Metadata(label = "configuration") +@XmlRootElement(name = "outputType") +@XmlAccessorType(XmlAccessType.FIELD) +public class OutputTypeDefinition extends OptionalIdentifiedDefinition<OutputTypeDefinition> { + @XmlAttribute(required = true) + private String urn; + @XmlTransient + private Class<?> clazz; + + public OutputTypeDefinition() { + } + + /** + * Get output type URN. + * @return output type URN + */ + public String getUrn() { + if (clazz != null) { + return "java:" + clazz.getName(); + } + return urn; + } + + /** + * Set output type URN. + * @param urn output type URN + * @return this OutputTypeDefinition instance + */ + public void setUrn(String urn) { + this.urn = urn; + } + + /** + * Set output type via Java Class. + * @param clazz Java Class + */ + public void setJavaClass(Class<?> clazz) { + this.clazz = clazz; + } + + @Override + public String toString() { + return "outputType[" + urn + "]"; + } + + @Override + public String getLabel() { + return "outputType[" + urn + "]"; + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/model/RouteDefinition.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/model/RouteDefinition.java b/camel-core/src/main/java/org/apache/camel/model/RouteDefinition.java index 83f51ef..e140dc0 100644 --- a/camel-core/src/main/java/org/apache/camel/model/RouteDefinition.java +++ b/camel-core/src/main/java/org/apache/camel/model/RouteDefinition.java @@ -46,6 +46,7 @@ import org.apache.camel.builder.RouteBuilder; import org.apache.camel.impl.DefaultRouteContext; import org.apache.camel.model.rest.RestDefinition; import org.apache.camel.processor.interceptor.HandleFault; +import org.apache.camel.spi.Contract; import org.apache.camel.spi.LifecycleStrategy; import org.apache.camel.spi.Metadata; import org.apache.camel.spi.RouteContext; @@ -61,7 +62,7 @@ import org.apache.camel.util.ObjectHelper; */ @Metadata(label = "configuration") @XmlRootElement(name = "route") -@XmlType(propOrder = {"inputs", "outputs"}) +@XmlType(propOrder = {"inputs", "inputType", "outputType", "outputs"}) @XmlAccessorType(XmlAccessType.PROPERTY) // must use XmlAccessType.PROPERTY as there is some custom logic needed to be executed in the setter methods public class RouteDefinition extends ProcessorDefinition<RouteDefinition> { @@ -87,6 +88,8 @@ public class RouteDefinition extends ProcessorDefinition<RouteDefinition> { private boolean contextScopedErrorHandler = true; private Boolean rest; private RestDefinition restDefinition; + private InputTypeDefinition inputType; + private OutputTypeDefinition outputType; public RouteDefinition() { } @@ -629,6 +632,50 @@ public class RouteDefinition extends ProcessorDefinition<RouteDefinition> { return this; } + /** + * Declare an input type. + * @param name input type URN + * @return the builder + */ + public RouteDefinition inputType(String name) { + inputType = new InputTypeDefinition(); + inputType.setUrn(name); + return this; + } + + /** + * Declare an input type with Java class. + * @param clazz Class object of the input type + * @return the builder + */ + public RouteDefinition inputType(Class clazz) { + inputType = new InputTypeDefinition(); + inputType.setJavaClass(clazz); + return this; + } + + /** + * Declare an output type. + * @param name output type URN + * @return the builder + */ + public RouteDefinition outputType(String name) { + outputType = new OutputTypeDefinition(); + outputType.setUrn(name); + return this; + } + + /** + * Declare an output type. + * @param clazz Class object of the output type + * @return the builder + */ + public RouteDefinition outputType(Class clazz) { + outputType = new OutputTypeDefinition(); + outputType.setJavaClass(clazz); + return this; + } + // Properties // ----------------------------------------------------------------------- @@ -935,6 +982,24 @@ public class RouteDefinition extends ProcessorDefinition<RouteDefinition> { return true; } + @XmlElementRef(required = false) + public void setInputType(InputTypeDefinition inputType) { + this.inputType = inputType; + } + + public InputTypeDefinition getInputType() { + return this.inputType; + } + + @XmlElementRef(required = false) + public void setOutputType(OutputTypeDefinition outputType) { + this.outputType = outputType; + } + + public OutputTypeDefinition getOutputType() { + return this.outputType; + } + // Implementation methods // ------------------------------------------------------------------------- protected RouteContext addRoutes(CamelContext camelContext, Collection<Route> routes, FromDefinition fromType) throws Exception { @@ -1062,6 +1127,18 @@ public class RouteDefinition extends ProcessorDefinition<RouteDefinition> { throw new FailedToCreateRouteException(route.getId(), route.toString(), at, cause); } + // add data type contract + if (inputType != null || outputType != null) { + Contract contract = new Contract(); + if (inputType != null) { + contract.setInputType(inputType.getUrn()); + } + if (outputType != null) { + contract.setOutputType(outputType.getUrn()); + } + routeContext.setContract(contract); + } + List<ProcessorDefinition<?>> list = new ArrayList<ProcessorDefinition<?>>(outputs); for (ProcessorDefinition<?> output : list) { try { @@ -1075,4 +1152,5 @@ public class RouteDefinition extends ProcessorDefinition<RouteDefinition> { routeContext.commit(); return routeContext; } + } http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/model/transformer/CustomTransformerDefinition.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/model/transformer/CustomTransformerDefinition.java b/camel-core/src/main/java/org/apache/camel/model/transformer/CustomTransformerDefinition.java new file mode 100644 index 0000000..3af804b --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/model/transformer/CustomTransformerDefinition.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.model.transformer; + +import java.util.Map; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAnyAttribute; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlTransient; +import javax.xml.bind.annotation.XmlType; +import javax.xml.namespace.QName; + +import org.apache.camel.CamelContext; +import org.apache.camel.Endpoint; +import org.apache.camel.component.bean.BeanHolder; +import org.apache.camel.component.bean.BeanProcessor; +import org.apache.camel.component.bean.ConstantStaticTypeBeanHolder; +import org.apache.camel.component.bean.ConstantTypeBeanHolder; +import org.apache.camel.impl.transformer.ProcessorTransformer; +import org.apache.camel.spi.DataFormat; +import org.apache.camel.spi.DataType; +import org.apache.camel.spi.Metadata; +import org.apache.camel.spi.RouteContext; +import org.apache.camel.spi.Transformer; +import org.apache.camel.util.ObjectHelper; + +/** + * Represents a BeanTransformer. + */ +@Metadata(label = "transformation") +@XmlType(name = "customTransformer") +@XmlAccessorType(XmlAccessType.FIELD) +public class CustomTransformerDefinition extends TransformerDefinition { + @XmlAttribute + private String ref; + @XmlAttribute + private String type; + + @Override + protected Transformer doCreateTransformer() throws Exception { + if (ref == null && type == null) { + throw new IllegalArgumentException("'ref' or 'type' must be specified for customTransformer"); + } + Transformer transformer; + if (ref != null) { + transformer = getCamelContext().getRegistry().lookupByNameAndType(ref, Transformer.class); + if (transformer == null) { + throw new IllegalArgumentException("Cannot find transformer with ref:" + ref); + } + if (transformer.getModel() != null || transformer.getFrom() != null || transformer.getTo() != null) { + throw new IllegalArgumentException(String.format("Transformer '%s' is already in use. Please check if duplicate transformer exists.", ref)); + } + } else { + Class<Transformer> transformerClass = getCamelContext().getClassResolver().resolveMandatoryClass(type, Transformer.class); + if (transformerClass == null) { + throw new IllegalArgumentException("Cannot find transformer class: " + type); + } + transformer = transformerClass.newInstance(); + } + transformer.setCamelContext(getCamelContext()); + return transformer.setModel(getScheme()) + .setFrom(getFrom()) + .setTo(getTo()); + } + + public String getRef() { + return ref; + } + + /** + * Set a bean reference of the Transformer + * @param ref the bean reference of the Transformer + */ + public void setRef(String ref) { + this.ref = ref; + } + + public String getType() { + return type; + } + + /** + * Set a class name of the Transformer + * @param ref the class name of the Transformer + */ + public void setType(String type) { + this.type = type; + } + +} + http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/model/transformer/DataFormatTransformerDefinition.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/model/transformer/DataFormatTransformerDefinition.java b/camel-core/src/main/java/org/apache/camel/model/transformer/DataFormatTransformerDefinition.java new file mode 100644 index 0000000..6429b85 --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/model/transformer/DataFormatTransformerDefinition.java @@ -0,0 +1,161 @@ +/** + * 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.model.transformer; + +import java.util.Map; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAnyAttribute; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElements; +import javax.xml.bind.annotation.XmlTransient; +import javax.xml.bind.annotation.XmlType; +import javax.xml.namespace.QName; + +import org.apache.camel.CamelContext; +import org.apache.camel.Endpoint; +import org.apache.camel.Message; +import org.apache.camel.impl.transformer.DataFormatTransformer; +import org.apache.camel.model.DataFormatDefinition; +import org.apache.camel.model.dataformat.AvroDataFormat; +import org.apache.camel.model.dataformat.Base64DataFormat; +import org.apache.camel.model.dataformat.BeanioDataFormat; +import org.apache.camel.model.dataformat.BindyDataFormat; +import org.apache.camel.model.dataformat.BoonDataFormat; +import org.apache.camel.model.dataformat.CastorDataFormat; +import org.apache.camel.model.dataformat.CryptoDataFormat; +import org.apache.camel.model.dataformat.CsvDataFormat; +import org.apache.camel.model.dataformat.CustomDataFormat; +import org.apache.camel.model.dataformat.FlatpackDataFormat; +import org.apache.camel.model.dataformat.GzipDataFormat; +import org.apache.camel.model.dataformat.HL7DataFormat; +import org.apache.camel.model.dataformat.IcalDataFormat; +import org.apache.camel.model.dataformat.JacksonXMLDataFormat; +import org.apache.camel.model.dataformat.JaxbDataFormat; +import org.apache.camel.model.dataformat.JibxDataFormat; +import org.apache.camel.model.dataformat.JsonDataFormat; +import org.apache.camel.model.dataformat.PGPDataFormat; +import org.apache.camel.model.dataformat.ProtobufDataFormat; +import org.apache.camel.model.dataformat.RssDataFormat; +import org.apache.camel.model.dataformat.SerializationDataFormat; +import org.apache.camel.model.dataformat.SoapJaxbDataFormat; +import org.apache.camel.model.dataformat.StringDataFormat; +import org.apache.camel.model.dataformat.SyslogDataFormat; +import org.apache.camel.model.dataformat.TarFileDataFormat; +import org.apache.camel.model.dataformat.TidyMarkupDataFormat; +import org.apache.camel.model.dataformat.UniVocityCsvDataFormat; +import org.apache.camel.model.dataformat.UniVocityFixedWidthDataFormat; +import org.apache.camel.model.dataformat.UniVocityTsvDataFormat; +import org.apache.camel.model.dataformat.XMLBeansDataFormat; +import org.apache.camel.model.dataformat.XMLSecurityDataFormat; +import org.apache.camel.model.dataformat.XStreamDataFormat; +import org.apache.camel.model.dataformat.XmlJsonDataFormat; +import org.apache.camel.model.dataformat.XmlRpcDataFormat; +import org.apache.camel.model.dataformat.ZipDataFormat; +import org.apache.camel.model.dataformat.ZipFileDataFormat; +import org.apache.camel.spi.DataFormat; +import org.apache.camel.spi.Metadata; +import org.apache.camel.spi.RouteContext; +import org.apache.camel.spi.Transformer; + +/** + * Represents a DataFormatTransformer. + */ +@Metadata(label = "transformation") +@XmlType(name = "dataFormatTransformer") +@XmlAccessorType(XmlAccessType.FIELD) +public class DataFormatTransformerDefinition extends TransformerDefinition { + + @XmlElements({ + @XmlElement(required = false, name = "avro", type = AvroDataFormat.class), + @XmlElement(required = false, name = "base64", type = Base64DataFormat.class), + @XmlElement(required = false, name = "beanio", type = BeanioDataFormat.class), + @XmlElement(required = false, name = "bindy", type = BindyDataFormat.class), + @XmlElement(required = false, name = "boon", type = BoonDataFormat.class), + @XmlElement(required = false, name = "castor", type = CastorDataFormat.class), + @XmlElement(required = false, name = "crypto", type = CryptoDataFormat.class), + @XmlElement(required = false, name = "csv", type = CsvDataFormat.class), + @XmlElement(required = false, name = "custom", type = CustomDataFormat.class), + @XmlElement(required = false, name = "flatpack", type = FlatpackDataFormat.class), + @XmlElement(required = false, name = "gzip", type = GzipDataFormat.class), + @XmlElement(required = false, name = "hl7", type = HL7DataFormat.class), + @XmlElement(required = false, name = "ical", type = IcalDataFormat.class), + @XmlElement(required = false, name = "jacksonxml", type = JacksonXMLDataFormat.class), + @XmlElement(required = false, name = "jaxb", type = JaxbDataFormat.class), + @XmlElement(required = false, name = "jibx", type = JibxDataFormat.class), + @XmlElement(required = false, name = "json", type = JsonDataFormat.class), + @XmlElement(required = false, name = "protobuf", type = ProtobufDataFormat.class), + @XmlElement(required = false, name = "rss", type = RssDataFormat.class), + @XmlElement(required = false, name = "secureXML", type = XMLSecurityDataFormat.class), + @XmlElement(required = false, name = "serialization", type = SerializationDataFormat.class), + @XmlElement(required = false, name = "soapjaxb", type = SoapJaxbDataFormat.class), + @XmlElement(required = false, name = "string", type = StringDataFormat.class), + @XmlElement(required = false, name = "syslog", type = SyslogDataFormat.class), + @XmlElement(required = false, name = "tarfile", type = TarFileDataFormat.class), + @XmlElement(required = false, name = "tidyMarkup", type = TidyMarkupDataFormat.class), + @XmlElement(required = false, name = "univocity-csv", type = UniVocityCsvDataFormat.class), + @XmlElement(required = false, name = "univocity-fixed", type = UniVocityFixedWidthDataFormat.class), + @XmlElement(required = false, name = "univocity-tsv", type = UniVocityTsvDataFormat.class), + @XmlElement(required = false, name = "xmlBeans", type = XMLBeansDataFormat.class), + @XmlElement(required = false, name = "xmljson", type = XmlJsonDataFormat.class), + @XmlElement(required = false, name = "xmlrpc", type = XmlRpcDataFormat.class), + @XmlElement(required = false, name = "xstream", type = XStreamDataFormat.class), + @XmlElement(required = false, name = "pgp", type = PGPDataFormat.class), + @XmlElement(required = false, name = "zip", type = ZipDataFormat.class), + @XmlElement(required = false, name = "zipFile", type = ZipFileDataFormat.class)} + ) + private DataFormatDefinition dataFormatType; + + @XmlAttribute + private String ref; + + @Override + protected Transformer doCreateTransformer() { + return new DataFormatTransformer(getCamelContext()) + .setDataFormatType(dataFormatType) + .setDataFormatRef(ref) + .setModel(getScheme()) + .setFrom(getFrom()) + .setTo(getTo()); + } + + public String getRef() { + return ref; + } + + /** + * Set the reference of the DataFormat. + * @param ref reference of the DataFormat + */ + public void setRef(String ref) { + this.ref = ref; + } + + public DataFormatDefinition getDataFormatType() { + return dataFormatType; + } + + /** + * The data format to be used + */ + public void setDataFormatType(DataFormatDefinition dataFormatType) { + this.dataFormatType = dataFormatType; + } + +} + http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/model/transformer/EndpointTransformerDefinition.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/model/transformer/EndpointTransformerDefinition.java b/camel-core/src/main/java/org/apache/camel/model/transformer/EndpointTransformerDefinition.java new file mode 100644 index 0000000..7b16fc4 --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/model/transformer/EndpointTransformerDefinition.java @@ -0,0 +1,88 @@ +/** + * 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.model.transformer; + +import java.util.Map; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAnyAttribute; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlTransient; +import javax.xml.bind.annotation.XmlType; +import javax.xml.namespace.QName; + +import org.apache.camel.CamelContext; +import org.apache.camel.Endpoint; +import org.apache.camel.ExchangePattern; +import org.apache.camel.impl.transformer.ProcessorTransformer; +import org.apache.camel.processor.SendProcessor; +import org.apache.camel.spi.DataFormat; +import org.apache.camel.spi.Metadata; +import org.apache.camel.spi.RouteContext; +import org.apache.camel.spi.Transformer; + +/** + * Represents a EndpointTransformer. + */ +@Metadata(label = "transformation") +@XmlType(name = "endpointTransformer") +@XmlAccessorType(XmlAccessType.FIELD) +public class EndpointTransformerDefinition extends TransformerDefinition { + + @XmlAttribute + private String ref; + @XmlAttribute + private String uri; + + @Override + protected Transformer doCreateTransformer() throws Exception { + Endpoint endpoint = uri != null ? getCamelContext().getEndpoint(uri) + : getCamelContext().getRegistry().lookupByNameAndType(ref, Endpoint.class); + SendProcessor processor = new SendProcessor(endpoint, ExchangePattern.InOut); + return new ProcessorTransformer(getCamelContext()) + .setProcessor(processor) + .setModel(getScheme()) + .setFrom(getFrom()) + .setTo(getTo()); + } + + public String getRef() { + return ref; + } + + /** + * Set the reference of the Endpoint. + * @param ref reference of the Endpoint + */ + public void setRef(String ref) { + this.ref = ref; + } + + public String getUri() { + return uri; + } + + /** + * Set the URI of the Endpoint. + * @param uri URI of the Endpoint + */ + public void setUri(String uri) { + this.uri = uri; + } + +} + http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/model/transformer/TransformerDefinition.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/model/transformer/TransformerDefinition.java b/camel-core/src/main/java/org/apache/camel/model/transformer/TransformerDefinition.java new file mode 100644 index 0000000..7695a63 --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/model/transformer/TransformerDefinition.java @@ -0,0 +1,133 @@ +/** + * 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.model.transformer; + +import java.util.Map; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAnyAttribute; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlTransient; +import javax.xml.bind.annotation.XmlType; +import javax.xml.namespace.QName; + +import org.apache.camel.CamelContext; +import org.apache.camel.Endpoint; +import org.apache.camel.model.IdentifiedType; +import org.apache.camel.model.OtherAttributesAware; +import org.apache.camel.spi.DataFormat; +import org.apache.camel.spi.DataType; +import org.apache.camel.spi.Metadata; +import org.apache.camel.spi.RouteContext; +import org.apache.camel.spi.Transformer; +import org.apache.camel.util.ObjectHelper; + +import static org.apache.camel.util.EndpointHelper.isReferenceParameter; + +/** + * Represents a Transformer. + */ +@Metadata(label = "transformation") +@XmlType(name = "transformer") +@XmlAccessorType(XmlAccessType.FIELD) +public abstract class TransformerDefinition { + @XmlAttribute + private String scheme; + @XmlAttribute + private String from; + @XmlAttribute + private String to; + @XmlTransient + private CamelContext camelContext; + + public Transformer createTransformer(CamelContext context) throws Exception { + this.camelContext = context; + return doCreateTransformer(); + }; + + protected abstract Transformer doCreateTransformer() throws Exception; + + public String getScheme() { + return scheme; + } + + /** + * Set a scheme name supported by the transformer. + * @param scheme scheme name + */ + public void setScheme(String scheme) { + this.scheme = scheme; + } + + public String getFrom() { + return from; + } + + /** + * Set the 'from' data type . + * @param from 'from' data type + */ + public void setFrom(String from) { + this.from = from; + } + + /** + * Set the 'from' data type using Java class. + * @param clazz 'from' Java class + */ + public void setFrom(Class<?> clazz) { + this.from = "java:" + clazz.getName(); + } + + public String getTo() { + return to; + } + + /** + * Set the 'to' data type. + * @param to 'to' data type + */ + public void setTo(String to) { + this.to = to; + } + + /** + * Set the 'to' data type using Java class. + * @param clazz 'to' Java class + */ + public void setTo(Class<?> clazz) { + this.to = "java:" + clazz.getName(); + } + + /** + * Get the CamelContext. + * @return + */ + public CamelContext getCamelContext() { + return camelContext; + } + + /** + * Set the CamelContext. + * @param camelContext CamelContext + */ + public void setCamelContext(CamelContext camelContext) { + this.camelContext = camelContext; + } + +} + http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/model/transformer/TransformersDefinition.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/model/transformer/TransformersDefinition.java b/camel-core/src/main/java/org/apache/camel/model/transformer/TransformersDefinition.java new file mode 100644 index 0000000..3820c0f --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/model/transformer/TransformersDefinition.java @@ -0,0 +1,58 @@ +/** + * 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.model.transformer; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElements; +import javax.xml.bind.annotation.XmlRootElement; + +import org.apache.camel.model.DataFormatDefinition; +import org.apache.camel.spi.Metadata; + +/** + * To configure transforms. + */ +@Metadata(label = "transformation", title = "Transformations") +@XmlRootElement(name = "transformers") +@XmlAccessorType(XmlAccessType.FIELD) +public class TransformersDefinition { + + @XmlElements({ + @XmlElement(required = false, name = "dataFormatTransformer", type = DataFormatTransformerDefinition.class), + @XmlElement(required = false, name = "endpointTransformer", type = EndpointTransformerDefinition.class), + @XmlElement(required = false, name = "customTransformer", type = CustomTransformerDefinition.class)} + ) + private List<TransformerDefinition> transforms; + + /** + * A list holding the configured transformations + */ + public void setTransformers(List<TransformerDefinition> transforms) { + this.transforms = transforms; + } + + public List<TransformerDefinition> getTransforms() { + return transforms; + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/model/transformer/package-info.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/model/transformer/package-info.java b/camel-core/src/main/java/org/apache/camel/model/transformer/package-info.java new file mode 100644 index 0000000..840ddb3 --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/model/transformer/package-info.java @@ -0,0 +1,24 @@ +/** + * 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. + */ + +/** + * The JAXB POJOs for the + * <a href="http://camel.apache.org/transformer.html">Transformers</a> used to transform message contents + * according to declared data types inside <a href="http://camel.apache.org/components.html">components</a> + */ +@javax.xml.bind.annotation.XmlSchema(namespace = "http://camel.apache.org/schema/spring", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED) +package org.apache.camel.model.transformer; http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/processor/CamelInternalProcessor.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/processor/CamelInternalProcessor.java b/camel-core/src/main/java/org/apache/camel/processor/CamelInternalProcessor.java index 50f2af4..ab9892a 100644 --- a/camel-core/src/main/java/org/apache/camel/processor/CamelInternalProcessor.java +++ b/camel-core/src/main/java/org/apache/camel/processor/CamelInternalProcessor.java @@ -26,6 +26,7 @@ import java.util.concurrent.RejectedExecutionException; import org.apache.camel.AsyncCallback; import org.apache.camel.CamelContext; import org.apache.camel.Exchange; +import org.apache.camel.Message; import org.apache.camel.MessageHistory; import org.apache.camel.Ordered; import org.apache.camel.Processor; @@ -40,11 +41,14 @@ import org.apache.camel.model.ProcessorDefinitionHelper; import org.apache.camel.processor.interceptor.BacklogDebugger; import org.apache.camel.processor.interceptor.BacklogTracer; import org.apache.camel.processor.interceptor.DefaultBacklogTracerEventMessage; +import org.apache.camel.spi.Contract; +import org.apache.camel.spi.DataType; import org.apache.camel.spi.InflightRepository; import org.apache.camel.spi.MessageHistoryFactory; import org.apache.camel.spi.RouteContext; import org.apache.camel.spi.RoutePolicy; import org.apache.camel.spi.StreamCachingStrategy; +import org.apache.camel.spi.Transformer; import org.apache.camel.spi.UnitOfWork; import org.apache.camel.util.MessageHelper; import org.apache.camel.util.OrderedComparator; @@ -854,4 +858,120 @@ public class CamelInternalProcessor extends DelegateAsyncProcessor { } } + /** + * Advice for data type contract + * TODO add declarative validation + */ + public static class ContractAdvice implements CamelInternalProcessorAdvice { + private Contract contract; + + public ContractAdvice(Contract contract) { + this.contract = contract; + } + + @Override + public Object before(Exchange exchange) throws Exception { + DataType from = getCurrentType(exchange, Exchange.INPUT_TYPE); + DataType to = contract.getInputType(); + if (to != null && !to.equals(from)) { + LOG.debug("Looking for transformer for INPUT: from='{}', to='{}'", from, to); + convertBody(exchange.getIn(), from, to); + exchange.setProperty(Exchange.INPUT_TYPE, to); + } + return null; + } + + @Override + public void after(Exchange exchange, Object data) throws Exception { + Message target = exchange.hasOut() ? exchange.getOut() : exchange.getIn(); + DataType from = getCurrentType(exchange, exchange.hasOut() ? Exchange.OUTPUT_TYPE : Exchange.INPUT_TYPE); + DataType to = contract.getOutputType(); + if (to != null && !to.equals(from)) { + LOG.debug("Looking for transformer for OUTPUT: from='{}', to='{}'", from, to); + convertBody(target, from, to); + exchange.setProperty(exchange.hasOut() ? Exchange.OUTPUT_TYPE : Exchange.INPUT_TYPE, to); + } + } + + private static void convertBody(Message message, DataType from, DataType to) throws Exception { + CamelContext context = message.getExchange().getContext(); + // transform into 'from' type before performing declared transformation + if (from != null && from.isJavaType() && from.getName() != null) { + Class<?> fromJava = getClazz(from.getName(), context); + if (!fromJava.isAssignableFrom(message.getBody().getClass())) { + LOG.debug("Converting to '{}'", fromJava.getName()); + Object fromBody = message.getMandatoryBody(fromJava); + message.setBody(fromBody); + } + } + + Transformer transformer = context.resolveTransformer(from, to); + if (transformer != null) { + // Applying exactly matched transformer. Java-Java transformer is also allowed. + LOG.debug("Applying transformer: from='{}', to='{}', transformer='{}'", from, to, transformer); + transformer.transform(message, from, to); + return; + } else if (from == null || from.isJavaType()) { + if (to.isJavaType() && to.getName() != null) { + // Java->Java transformation just relies on TypeConverter if no declared transformer + // TODO for better performance it may be better to add TypeConveterTransformer + // into transformer registry to avoid unnecessary scan in transformer registry + LOG.debug("Converting to '{}'", to.getName()); + Object answer = message.getMandatoryBody(getClazz(to.getName(), context)); + message.setBody(answer); + return; + } else if (from == null) { + // {undefined}->Other transformation - assuming it's already in expected shape + return; + } else { + // Java->Other transformation + transformer = context.resolveTransformer(to.getModel()); + if (transformer != null) { + LOG.debug("Applying transformer: from='{}', to='{}', transformer='{}'", from, to, transformer); + transformer.transform(message, from, to); + return; + } + } + } else if (from != null) { + if (to.isJavaType()) { + // Other->Java transformation + transformer = context.resolveTransformer(from.getModel()); + if (transformer != null) { + LOG.debug("Applying transformer: from='{}', to='{}', transformer='{}'", from, to, transformer); + transformer.transform(message, from, to); + return; + } + } else { + // Other->Other transformation - look for a transformer chain + Transformer fromTransformer = context.resolveTransformer(from.getModel()); + Transformer toTransformer = context.resolveTransformer(to.getModel()); + if (fromTransformer != null && toTransformer != null) { + LOG.debug("Applying transformer: from='{}', to='{}', transformer='{}'", from, to, transformer); + fromTransformer.transform(message, from, new DataType(Object.class)); + LOG.debug("Applying transformer: from='{}', to='{}', transformer='{}'", from, to, transformer); + toTransformer.transform(message, new DataType(Object.class), to); + return; + } + } + } + + throw new IllegalArgumentException("No Transformer found for [from='" + from + "', to='" + to + "']"); + } + + private static Class<?> getClazz(String type, CamelContext context) throws Exception { + return context.getClassResolver().resolveMandatoryClass(type); + } + + private static DataType getCurrentType(Exchange exchange, String name) { + Object prop = exchange.getProperty(name); + if (prop instanceof DataType) { + return (DataType)prop; + } else if (prop instanceof String) { + DataType answer = new DataType((String)prop); + exchange.setProperty(name, answer); + return answer; + } + return null; + } + } } http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/spi/Contract.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/spi/Contract.java b/camel-core/src/main/java/org/apache/camel/spi/Contract.java new file mode 100644 index 0000000..0706023 --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/spi/Contract.java @@ -0,0 +1,112 @@ +/** + * 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.spi; + +import java.util.Map; +import javax.xml.namespace.QName; + +/** + * A Contract which represents the input type and/or output type of the {@link Endpoint} or {@link Processor}. + */ +public class Contract { + + private DataType inputType; + private DataType outputType; + private String contractString; + + public DataType getInputType() { + return inputType; + } + + /** + * Set the input data type. + * @param inputType input data type + */ + public void setInputType(String inputType) { + this.inputType = new DataType(inputType); + this.contractString = null; + } + + /** + * Set the input data type with Java class. + * @param clazz Java class which represents input data type + */ + public void setInputType(Class<?> clazz) { + this.inputType = new DataType(clazz); + this.contractString = null; + } + + public DataType getOutputType() { + return outputType; + } + + /** + * Set the output data type. + * @param outputType output data type + */ + public void setOutputType(String outputType) { + this.outputType = new DataType(outputType); + this.contractString = null; + } + + /** + * Set the output data type with Java class. + * @param clazz Java class which represents output data type + */ + public void setOutputType(Class<?> clazz) { + this.outputType = new DataType(clazz); + this.contractString = null; + } + + @Override + public String toString() { + if (contractString == null) { + this.contractString = "DataType[input=" + this.inputType + ", output=" + this.outputType + "]"; + } + return contractString; + } + + public boolean isEmpty() { + return inputType == null && outputType == null; + } + + @Override + public boolean equals(Object target) { + if (!(target instanceof Contract)) { + return false; + } + Contract targetContract = (Contract)target; + if (getInputType() != null || targetContract.getInputType() != null) { + if (getInputType() == null || targetContract.getInputType() == null + || !getInputType().equals(targetContract.getInputType())) { + return false; + } + } + if (getOutputType() != null || targetContract.getOutputType() != null) { + if (getOutputType() == null || targetContract.getOutputType() == null + || !getOutputType().equals(targetContract.getOutputType())) { + return false; + } + } + return true; + } + + @Override + public int hashCode() { + return toString().hashCode(); + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/spi/DataType.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/spi/DataType.java b/camel-core/src/main/java/org/apache/camel/spi/DataType.java new file mode 100644 index 0000000..3efae96 --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/spi/DataType.java @@ -0,0 +1,89 @@ +/** + * 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.spi; + +import org.apache.camel.util.StringHelper; + +/** + * Represents the data type URN which is used for message data type contract. + */ +public class DataType { + + private String model; + private String name; + private boolean isJavaType; + private String typeString; + + public DataType(String urn) { + if (urn != null) { + String split[] = StringHelper.splitOnCharacter(urn, ":", 2); + model = split[0]; + isJavaType = model.equals("java"); + if (split.length > 1) { + name = split[1]; + } + } + } + + public DataType(Class<?> clazz) { + model = "java"; + isJavaType = true; + name = clazz.getName(); + } + + public String getModel() { + return model; + } + + public String getName() { + return name; + } + + public boolean isJavaType() { + return isJavaType; + } + + @Override + public String toString() { + if (this.typeString == null) { + this.typeString = model + ":" + name; + } + return this.typeString; + } + + @Override + public boolean equals(Object target) { + if (target instanceof DataType) { + DataType targetdt = (DataType)target; + String targetModel = targetdt.getModel(); + String targetName = targetdt.getName(); + if (targetModel == null) { + return false; + } else if (targetName == null) { + return targetModel.equals(getModel()) && getName() == null; + } else { + return targetModel.equals(getModel()) && targetName.equals(getName()); + } + } + return false; + } + + @Override + public int hashCode() { + return toString().hashCode(); + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/spi/RouteContext.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/spi/RouteContext.java b/camel-core/src/main/java/org/apache/camel/spi/RouteContext.java index 54e6ad0..194f544 100644 --- a/camel-core/src/main/java/org/apache/camel/spi/RouteContext.java +++ b/camel-core/src/main/java/org/apache/camel/spi/RouteContext.java @@ -192,4 +192,9 @@ public interface RouteContext extends RuntimeConfiguration, EndpointAware { */ int getAndIncrement(ProcessorDefinition<?> node); + /** + * + * @param contract + */ + void setContract(Contract contract); } http://git-wip-us.apache.org/repos/asf/camel/blob/7ba090f5/camel-core/src/main/java/org/apache/camel/spi/Transformer.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/spi/Transformer.java b/camel-core/src/main/java/org/apache/camel/spi/Transformer.java new file mode 100644 index 0000000..adee678 --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/spi/Transformer.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.spi; + +import java.io.InputStream; +import java.io.OutputStream; + +import org.apache.camel.CamelContext; +import org.apache.camel.CamelContextAware; +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.apache.camel.support.ServiceSupport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * <a href="http://camel.apache.org/transformer.html">Transformer</a> + * represents Any to Any data transformation which leverages data format and endpoint + * under the cover. + */ +public abstract class Transformer extends ServiceSupport implements CamelContextAware { + + private CamelContext camelContext; + private String model; + private DataType from; + private DataType to; + + /** + * Perform data transformation with specified from/to type. + * @param message message to apply transformation + * @param from 'from' data type + * @param to 'to' data type + */ + public abstract void transform(Message message, DataType from, DataType to) throws Exception; + + /** + * Get a data model which is supported by this transformer. + * @return data model + */ + public String getModel() { + return model; + }; + + /** + * Get 'from' data type. + * @return 'from' data type + */ + public DataType getFrom() { + return from; + }; + + /** + * Get 'to' data type. + * @return 'to' data type + */ + public DataType getTo() { + return to; + }; + + /** + * Set data model. + * @param model data model + * @return this Transformer instance + */ + public Transformer setModel(String model) { + this.model = model; + return this; + } + + /** + * Set 'from' data type. + * @param from 'from' data type + * @return this Transformer instance + */ + public Transformer setFrom(String from) { + this.from = new DataType(from); + return this; + } + + /** + * Set 'to' data type. + * @param to 'to' data type + * @return this Transformer instance + */ + public Transformer setTo(String to) { + this.to = new DataType(to); + return this; + } + + @Override + public CamelContext getCamelContext() { + return this.camelContext; + } + + @Override + public void setCamelContext(CamelContext context) { + this.camelContext = context; + } + + @Override + public String toString() { + return String.format("%s[model='%s', from='%s', to='%s']", this.getClass().getSimpleName(), from, to); + } + + @Override + protected void doStart() throws Exception { + // no-op + } + + @Override + protected void doStop() throws Exception { + // no-op + } +}