diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/AbstractMessageChannelBinder.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/AbstractMessageChannelBinder.java index db24919d0..977c47e05 100644 --- a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/AbstractMessageChannelBinder.java +++ b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/AbstractMessageChannelBinder.java @@ -17,6 +17,10 @@ package org.springframework.cloud.stream.binder; import org.springframework.beans.factory.InitializingBean; +import org.springframework.cloud.stream.provisioning.ConsumerDestination; +import org.springframework.cloud.stream.provisioning.ProducerDestination; +import org.springframework.cloud.stream.provisioning.ProvisioningException; +import org.springframework.cloud.stream.provisioning.ProvisioningProvider; import org.springframework.context.Lifecycle; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; @@ -38,21 +42,18 @@ import org.springframework.util.MimeType; * {@link AbstractBinder} that serves as base class for {@link MessageChannel} * binders. Implementors must implement the following methods: * * * @param the consumer properties type * @param

the producer properties type - * @param the consumer destination type - * @param the producer destination type * @author Marius Bogoevici * @author Ilayaperumal Gopinathan + * @author Soby Chacko * @since 1.1 */ -public abstract class AbstractMessageChannelBinder +public abstract class AbstractMessageChannelBinder extends AbstractBinder { protected static final ExpressionParser EXPRESSION_PARSER = new SpelExpressionParser(); @@ -73,18 +74,22 @@ public abstract class AbstractMessageChannelBinder provisioningProvider; + + public AbstractMessageChannelBinder(boolean supportsHeadersNatively, String[] headersToEmbed, + ProvisioningProvider provisioningProvider) { this.supportsHeadersNatively = supportsHeadersNatively; this.headersToEmbed = headersToEmbed; + this.provisioningProvider = provisioningProvider; } /** * Binds an outbound channel to a given destination. The implementation delegates to - * {@link #createProducerDestinationIfNecessary(String, ProducerProperties)} - * and {@link #createProducerMessageHandler(PD, ProducerProperties)} for + * {@link ProvisioningProvider#provisionProducerDestination(String, ProducerProperties)} + * and {@link #createProducerMessageHandler(ProducerDestination, ProducerProperties)} for * handling the middleware specific logic. If the returned producer message handler is an * {@link InitializingBean} then {@link InitializingBean#afterPropertiesSet()} will be - * called on it. Similarly, if the returned producer message handler endpoint is a + * called on it. Similarly, if the returned producer message handler e ndpoint is a * {@link Lifecycle}, then {@link Lifecycle#start()} will be called on it. * * @param destination the name of the destination @@ -98,9 +103,10 @@ public abstract class AbstractMessageChannelBinderxyz and it is provisioned with 4 partitions, there may be + * 4 different destinations on the broker such as - xyz-0, xyz-1, xyz-2 and xyz-3. + * This behavior is dependent on the broker and the way the corresponding binder implements the logic. + * + * On certain brokers (for instance, Kafka), this behavior is completely skipped + * and there is a one-to-one correspondence between the destination name in the provisioner and + * the physical destination on the broker. + * + * @param partition the partition to find destination for + * @return destination name for the given partition + */ + String getNameForPartition(int partition); +} diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/provisioning/ProvisioningException.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/provisioning/ProvisioningException.java new file mode 100644 index 000000000..343eddb13 --- /dev/null +++ b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/provisioning/ProvisioningException.java @@ -0,0 +1,49 @@ +/* + * Copyright 2015-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.stream.provisioning; + +import org.springframework.core.NestedRuntimeException; + +/** + * Generic unchecked exception to wrap middleware or technology specific exceptions. + * Wrapped exceptions could be either checked or unchecked. + * + * See {@link NestedRuntimeException} for more usage details. + * + * @author Soby Chacko + */ +@SuppressWarnings("serial") +public class ProvisioningException extends NestedRuntimeException { + + /** + * Constructor that takes a message. + * @param msg the detail message + */ + public ProvisioningException(String msg) { + super(msg); + } + + /** + * Constructor that takes a message and a root cause. + * @param msg the detail message + * @param cause the cause of the exception. This argument is generally + * expected to be middleware specific. + */ + public ProvisioningException(String msg, Throwable cause) { + super(msg, cause); + } +} diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/provisioning/ProvisioningProvider.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/provisioning/ProvisioningProvider.java new file mode 100644 index 000000000..9b80d2592 --- /dev/null +++ b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/provisioning/ProvisioningProvider.java @@ -0,0 +1,66 @@ +/* + * Copyright 2015-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.stream.provisioning; + +import org.springframework.cloud.stream.binder.ConsumerProperties; +import org.springframework.cloud.stream.binder.ProducerProperties; + +/** + * Provisioning SPI that allows the users to provision destinations such as queues and topics. + * This SPI will allow the binders to be separated from any provisioning concerns and only focus + * on setting up endpoints for sending/receiving messages. + * + * Implementations must implement the following methods: + * + *

+ * + * @param the consumer properties type + * @param

the producer properties type + * + * @author Soby Chacko + * + * @since 1.2 + */ +public interface ProvisioningProvider { + + /** + * Creates middleware destination on the physical broker for the producer to send data. The implementation + * is middleware-specific. + * + * @param name the name of the producer destination + * @param properties producer properties + * @return reference to {@link ProducerDestination} that represents a producer + * @throws ProvisioningException on underlying provisioning errors from the middleware + */ + ProducerDestination provisionProducerDestination(String name, P properties) throws ProvisioningException; + + /** + * Creates the middleware destination on the physical broker for the consumer to consume data. + * The implementation is middleware-specific. + * + * @param name the name of the destination + * @param group the consumer group + * @param properties consumer properties + * @return reference to {@link ConsumerDestination} that represents a consumer + * @throws ProvisioningException on underlying provisioning errors from the middleware + */ + ConsumerDestination provisionConsumerDestination(String name, String group, C properties) throws ProvisioningException; + +}