#98 - Add support for AbstractRoutingConnectionFactory.
We now provide an abstract base class for ConnectionFactory routing. Routing keys are typically obtained from a subscriber context. AbstractRoutingConnectionFactory is backed by either a map of string identifiers or connection factories. When using string identifiers, these can map agains e.g. Spring bean names that can be resolved using BeanFactoryConnectionFactoryLookup.
class MyRoutingConnectionFactory extends AbstractRoutingConnectionFactory {
@Override
protected Mono<Object> determineCurrentLookupKey() {
return Mono.subscriberContext().filter(it -> it.hasKey(ROUTING_KEY)).map(it -> it.get(ROUTING_KEY));
}
}
@Bean
public void routingConnectionFactory() {
MyRoutingConnectionFactory router = new MyRoutingConnectionFactory();
Map<String, ConnectionFactory> factories = new HashMap<>();
ConnectionFactory myDefault = …;
ConnectionFactory primary = …;
ConnectionFactory secondary = …;
factories.put("primary", primary);
factories.put("secondary", secondary);
router.setTargetConnectionFactories(factories);
router.setDefaultTargetConnectionFactory(myDefault);
return router;
}
Original pull request: #132.
This commit is contained in:
committed by
Jens Schauder
parent
16d4a66f6a
commit
e3aae619f4
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* Copyright 2019 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
|
||||
*
|
||||
* https://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.data.r2dbc.connectionfactory.lookup;
|
||||
|
||||
import io.r2dbc.spi.Connection;
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
import io.r2dbc.spi.ConnectionFactoryMetadata;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Abstract {@link ConnectionFactory} implementation that routes {@link #create()} calls to one of various target
|
||||
* {@link ConnectionFactory factories} based on a lookup key. The latter is typically (but not necessarily) determined
|
||||
* from some subscriber context.
|
||||
* <p>
|
||||
* Allows to configure a {@link #setDefaultTargetConnectionFactory(Object) default ConnectionFactory} as fallback.
|
||||
* <p>
|
||||
* Calls to {@link #getMetadata()} are routed to the {@link #setDefaultTargetConnectionFactory(Object) default
|
||||
* ConnectionFactory} if configured.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @see #setTargetConnectionFactories
|
||||
* @see #setDefaultTargetConnectionFactory
|
||||
* @see #determineCurrentLookupKey()
|
||||
*/
|
||||
public abstract class AbstractRoutingConnectionFactory implements ConnectionFactory, InitializingBean {
|
||||
|
||||
private static final Object FALLBACK_MARKER = new Object();
|
||||
|
||||
private @Nullable Map<Object, Object> targetConnectionFactories;
|
||||
|
||||
private @Nullable Object defaultTargetConnectionFactory;
|
||||
|
||||
private boolean lenientFallback = true;
|
||||
|
||||
private ConnectionFactoryLookup connectionFactoryLookup = new MapConnectionFactoryLookup();
|
||||
|
||||
private @Nullable Map<Object, ConnectionFactory> resolvedConnectionFactories;
|
||||
|
||||
private @Nullable ConnectionFactory resolvedDefaultConnectionFactory;
|
||||
|
||||
/**
|
||||
* Specify the map of target {@link ConnectionFactory ConnectionFactories}, with the lookup key as key. The mapped
|
||||
* value can either be a corresponding {@link ConnectionFactory} instance or a connection factory name String (to be
|
||||
* resolved via a {@link #setConnectionFactoryLookup ConnectionFactoryLookup}).
|
||||
* <p>
|
||||
* The key can be of arbitrary type; this class implements the generic lookup process only. The concrete key
|
||||
* representation will be handled by {@link #resolveSpecifiedLookupKey(Object)} and
|
||||
* {@link #determineCurrentLookupKey()}.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setTargetConnectionFactories(Map<?, ?> targetConnectionFactories) {
|
||||
this.targetConnectionFactories = (Map) targetConnectionFactories;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the default target {@link ConnectionFactory}, if any.
|
||||
* <p>
|
||||
* The mapped value can either be a corresponding {@link ConnectionFactory} instance or a connection factory name
|
||||
* {@link String} (to be resolved via a {@link #setConnectionFactoryLookup ConnectionFactoryLookup}).
|
||||
* <p>
|
||||
* This {@link ConnectionFactory} will be used as target if none of the keyed {@link #setTargetConnectionFactories
|
||||
* targetConnectionFactories} match the {@link #determineCurrentLookupKey()} current lookup key.
|
||||
*/
|
||||
public void setDefaultTargetConnectionFactory(Object defaultTargetConnectionFactory) {
|
||||
this.defaultTargetConnectionFactory = defaultTargetConnectionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether to apply a lenient fallback to the default {@link ConnectionFactory} if no specific
|
||||
* {@link ConnectionFactory} could be found for the current lookup key.
|
||||
* <p>
|
||||
* Default is {@literal true}, accepting lookup keys without a corresponding entry in the target
|
||||
* {@link ConnectionFactory} map - simply falling back to the default {@link ConnectionFactory} in that case.
|
||||
* <p>
|
||||
* Switch this flag to {@literal false} if you would prefer the fallback to only apply no lookup key was emitted.
|
||||
* Lookup keys without a {@link ConnectionFactory} entry will then lead to an {@link IllegalStateException}.
|
||||
*
|
||||
* @see #setTargetConnectionFactories
|
||||
* @see #setDefaultTargetConnectionFactory
|
||||
* @see #determineCurrentLookupKey()
|
||||
*/
|
||||
public void setLenientFallback(boolean lenientFallback) {
|
||||
this.lenientFallback = lenientFallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link ConnectionFactoryLookup} implementation to use for resolving connection factory name Strings in the
|
||||
* {@link #setTargetConnectionFactories targetConnectionFactories} map.
|
||||
*/
|
||||
public void setConnectionFactoryLookup(ConnectionFactoryLookup connectionFactoryLookup) {
|
||||
|
||||
Assert.notNull(connectionFactoryLookup, "ConnectionFactoryLookup must not be null!");
|
||||
|
||||
this.connectionFactoryLookup = connectionFactoryLookup;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
|
||||
Assert.notNull(this.targetConnectionFactories, "Property 'targetConnectionFactories' must not be null!");
|
||||
|
||||
this.resolvedConnectionFactories = new HashMap<>(this.targetConnectionFactories.size());
|
||||
this.targetConnectionFactories.forEach((key, value) -> {
|
||||
Object lookupKey = resolveSpecifiedLookupKey(key);
|
||||
ConnectionFactory connectionFactory = resolveSpecifiedConnectionFactory(value);
|
||||
this.resolvedConnectionFactories.put(lookupKey, connectionFactory);
|
||||
});
|
||||
|
||||
if (this.defaultTargetConnectionFactory != null) {
|
||||
this.resolvedDefaultConnectionFactory = resolveSpecifiedConnectionFactory(this.defaultTargetConnectionFactory);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the given lookup key object, as specified in the {@link #setTargetConnectionFactories
|
||||
* targetConnectionFactories} map, into the actual lookup key to be used for matching with the
|
||||
* {@link #determineCurrentLookupKey() current lookup key}.
|
||||
* <p>
|
||||
* The default implementation simply returns the given key as-is.
|
||||
*
|
||||
* @param lookupKey the lookup key object as specified by the user.
|
||||
* @return the lookup key as needed for matching.
|
||||
*/
|
||||
protected Object resolveSpecifiedLookupKey(Object lookupKey) {
|
||||
return lookupKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the specified connection factory object into a {@link ConnectionFactory} instance.
|
||||
* <p>
|
||||
* The default implementation handles {@link ConnectionFactory} instances and connection factory names (to be resolved
|
||||
* via a {@link #setConnectionFactoryLookup ConnectionFactoryLookup}).
|
||||
*
|
||||
* @param connectionFactory the connection factory value object as specified in the
|
||||
* {@link #setTargetConnectionFactories targetConnectionFactories} map.
|
||||
* @return the resolved {@link ConnectionFactory} (never {@literal null}).
|
||||
* @throws IllegalArgumentException in case of an unsupported value type.
|
||||
*/
|
||||
protected ConnectionFactory resolveSpecifiedConnectionFactory(Object connectionFactory)
|
||||
throws IllegalArgumentException {
|
||||
|
||||
if (connectionFactory instanceof ConnectionFactory) {
|
||||
return (ConnectionFactory) connectionFactory;
|
||||
} else if (connectionFactory instanceof String) {
|
||||
return this.connectionFactoryLookup.getConnectionFactory((String) connectionFactory);
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Illegal connection factory value - only 'io.r2dbc.spi.ConnectionFactory' and 'String' supported: "
|
||||
+ connectionFactory);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see io.r2dbc.spi.ConnectionFactory#create()
|
||||
*/
|
||||
@Override
|
||||
public Mono<Connection> create() {
|
||||
|
||||
return determineTargetConnectionFactory() //
|
||||
.map(ConnectionFactory::create) //
|
||||
.flatMap(Mono::from);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see io.r2dbc.spi.ConnectionFactory#getMetadata()
|
||||
*/
|
||||
@Override
|
||||
public ConnectionFactoryMetadata getMetadata() {
|
||||
|
||||
if (this.resolvedDefaultConnectionFactory != null) {
|
||||
return this.resolvedDefaultConnectionFactory.getMetadata();
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException(
|
||||
"No default ConnectionFactory configured to retrieve ConnectionFactoryMetadata");
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the current target {@link ConnectionFactory}. Determines the {@link #determineCurrentLookupKey() current
|
||||
* lookup key}, performs a lookup in the {@link #setTargetConnectionFactories targetConnectionFactories} map, falls
|
||||
* back to the specified {@link #setDefaultTargetConnectionFactory default target ConnectionFactory} if necessary.
|
||||
*
|
||||
* @see #determineCurrentLookupKey()
|
||||
* @return {@link Mono} emitting the current {@link ConnectionFactory} as per {@link #determineCurrentLookupKey()}.
|
||||
*/
|
||||
protected Mono<ConnectionFactory> determineTargetConnectionFactory() {
|
||||
|
||||
Assert.state(this.resolvedConnectionFactories != null, "ConnectionFactory router not initialized");
|
||||
|
||||
Mono<Object> lookupKey = determineCurrentLookupKey().defaultIfEmpty(FALLBACK_MARKER);
|
||||
|
||||
return lookupKey.handle((key, sink) -> {
|
||||
|
||||
ConnectionFactory connectionFactory = this.resolvedConnectionFactories.get(key);
|
||||
|
||||
if (connectionFactory == null && (key == FALLBACK_MARKER || this.lenientFallback)) {
|
||||
connectionFactory = this.resolvedDefaultConnectionFactory;
|
||||
}
|
||||
|
||||
if (connectionFactory == null) {
|
||||
sink.error(new IllegalStateException(String.format(
|
||||
"Cannot determine target ConnectionFactory for lookup key '%s'", key == FALLBACK_MARKER ? null : key)));
|
||||
return;
|
||||
}
|
||||
|
||||
sink.next(connectionFactory);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the current lookup key. This will typically be implemented to check a subscriber context. Allows for
|
||||
* arbitrary keys. The returned key needs to match the stored lookup key type, as resolved by the
|
||||
* {@link #resolveSpecifiedLookupKey} method.
|
||||
*
|
||||
* @return {@link Mono} emitting the lookup key. May complete without emitting a value if no lookup key available.
|
||||
*/
|
||||
protected abstract Mono<Object> determineCurrentLookupKey();
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2019 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
|
||||
*
|
||||
* https://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.data.r2dbc.connectionfactory.lookup;
|
||||
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link ConnectionFactoryLookup} implementation based on a Spring {@link BeanFactory}.
|
||||
* <p>
|
||||
* Will lookup Spring managed beans identified by bean name, expecting them to be of type {@link ConnectionFactory}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @see BeanFactory
|
||||
*/
|
||||
public class BeanFactoryConnectionFactoryLookup implements ConnectionFactoryLookup, BeanFactoryAware {
|
||||
|
||||
@Nullable private BeanFactory beanFactory;
|
||||
|
||||
/**
|
||||
* Creates a new {@link BeanFactoryConnectionFactoryLookup} instance.
|
||||
* <p>
|
||||
* The {@link BeanFactory} to access must be set via {@code setBeanFactory}.
|
||||
*
|
||||
* @see #setBeanFactory
|
||||
*/
|
||||
public BeanFactoryConnectionFactoryLookup() {}
|
||||
|
||||
/**
|
||||
* Create a new instance of the {@link BeanFactoryConnectionFactoryLookup} class.
|
||||
* <p>
|
||||
* Use of this constructor is redundant if this object is being created by a Spring IoC container, as the supplied
|
||||
* {@link BeanFactory} will be replaced by the {@link BeanFactory} that creates it (see the {@link BeanFactoryAware}
|
||||
* contract). So only use this constructor if you are using this class outside the context of a Spring IoC container.
|
||||
*
|
||||
* @param beanFactory the bean factory to be used to lookup {@link ConnectionFactory ConnectionFactories}.
|
||||
*/
|
||||
public BeanFactoryConnectionFactoryLookup(BeanFactory beanFactory) {
|
||||
|
||||
Assert.notNull(beanFactory, "BeanFactory must not be null!");
|
||||
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.BeanFactoryAware#setBeanFactory(org.springframework.beans.factory.BeanFactory)
|
||||
*/
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.r2dbc.connectionfactory.lookup.ConnectionFactoryLookup#getConnectionFactory(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public ConnectionFactory getConnectionFactory(String connectionFactoryName)
|
||||
throws ConnectionFactoryLookupFailureException {
|
||||
|
||||
Assert.state(this.beanFactory != null, "BeanFactory must not be null!");
|
||||
|
||||
try {
|
||||
return this.beanFactory.getBean(connectionFactoryName, ConnectionFactory.class);
|
||||
} catch (BeansException ex) {
|
||||
throw new ConnectionFactoryLookupFailureException(
|
||||
String.format("Failed to look up ConnectionFactory bean with name '%s'", connectionFactoryName), ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2019 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
|
||||
*
|
||||
* https://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.data.r2dbc.connectionfactory.lookup;
|
||||
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
|
||||
/**
|
||||
* Strategy interface for looking up {@link ConnectionFactory} by name.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ConnectionFactoryLookup {
|
||||
|
||||
/**
|
||||
* Retrieve the {@link ConnectionFactory} identified by the given name.
|
||||
*
|
||||
* @param connectionFactoryName the name of the {@link ConnectionFactory}.
|
||||
* @return the {@link ConnectionFactory} (never {@literal null}).
|
||||
* @throws ConnectionFactoryLookupFailureException if the lookup failed.
|
||||
*/
|
||||
ConnectionFactory getConnectionFactory(String connectionFactoryName) throws ConnectionFactoryLookupFailureException;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2019 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
|
||||
*
|
||||
* https://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.data.r2dbc.connectionfactory.lookup;
|
||||
|
||||
import org.springframework.dao.NonTransientDataAccessException;
|
||||
|
||||
/**
|
||||
* Exception to be thrown by a {@link ConnectionFactoryLookup} implementation, indicating that the specified
|
||||
* {@link io.r2dbc.spi.ConnectionFactory} could not be obtained.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class ConnectionFactoryLookupFailureException extends NonTransientDataAccessException {
|
||||
|
||||
/**
|
||||
* Constructor for {@link ConnectionFactoryLookupFailureException}.
|
||||
*
|
||||
* @param msg the detail message.
|
||||
*/
|
||||
public ConnectionFactoryLookupFailureException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for {@link ConnectionFactoryLookupFailureException}.
|
||||
*
|
||||
* @param msg the detail message.
|
||||
* @param cause the root cause.
|
||||
*/
|
||||
public ConnectionFactoryLookupFailureException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright 2019 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
|
||||
*
|
||||
* https://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.data.r2dbc.connectionfactory.lookup;
|
||||
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Simple {@link ConnectionFactoryLookup} implementation that relies on a map for doing lookups.
|
||||
* <p>
|
||||
* Useful for testing environments or applications that need to match arbitrary {@link String} names to target
|
||||
* {@link ConnectionFactory} objects.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class MapConnectionFactoryLookup implements ConnectionFactoryLookup {
|
||||
|
||||
private final Map<String, ConnectionFactory> connectionFactories = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Create a new instance of the {@link MapConnectionFactoryLookup} class.
|
||||
*/
|
||||
public MapConnectionFactoryLookup() {}
|
||||
|
||||
/**
|
||||
* Create a new instance of the {@link MapConnectionFactoryLookup} class.
|
||||
*
|
||||
* @param connectionFactories the {@link Map} of {@link ConnectionFactory}. The keys are {@link String Strings}, the
|
||||
* values are actual {@link ConnectionFactory} instances.
|
||||
*/
|
||||
public MapConnectionFactoryLookup(Map<String, ConnectionFactory> connectionFactories) {
|
||||
setConnectionFactories(connectionFactories);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of the {@link MapConnectionFactoryLookup} class.
|
||||
*
|
||||
* @param connectionFactoryName the name under which the supplied {@link ConnectionFactory} is to be added
|
||||
* @param connectionFactory the {@link ConnectionFactory} to be added
|
||||
*/
|
||||
public MapConnectionFactoryLookup(String connectionFactoryName, ConnectionFactory connectionFactory) {
|
||||
addConnectionFactory(connectionFactoryName, connectionFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link Map} of {@link ConnectionFactory ConnectionFactories}. The keys are {@link String Strings}, the
|
||||
* values are actual {@link ConnectionFactory} instances.
|
||||
* <p>
|
||||
* If the supplied {@link Map} is {@code null}, then this method call effectively has no effect.
|
||||
*
|
||||
* @param connectionFactories said {@link Map} of {@link ConnectionFactory connectionFactories}
|
||||
*/
|
||||
public void setConnectionFactories(Map<String, ConnectionFactory> connectionFactories) {
|
||||
|
||||
Assert.notNull(connectionFactories, "ConnectionFactories must not be null!");
|
||||
|
||||
this.connectionFactories.putAll(connectionFactories);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link Map} of {@link ConnectionFactory ConnectionFactories} maintained by this object.
|
||||
* <p>
|
||||
* The returned {@link Map} is {@link Collections#unmodifiableMap(Map) unmodifiable}.
|
||||
*
|
||||
* @return {@link Map} of {@link ConnectionFactory connectionFactory} (never {@literal null}).
|
||||
*/
|
||||
public Map<String, ConnectionFactory> getConnectionFactories() {
|
||||
return Collections.unmodifiableMap(this.connectionFactories);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the supplied {@link ConnectionFactory} to the map of {@link ConnectionFactory ConnectionFactorys} maintained by
|
||||
* this object.
|
||||
*
|
||||
* @param connectionFactoryName the name under which the supplied {@link ConnectionFactory} is to be added
|
||||
* @param connectionFactory the {@link ConnectionFactory} to be so added
|
||||
*/
|
||||
public void addConnectionFactory(String connectionFactoryName, ConnectionFactory connectionFactory) {
|
||||
|
||||
Assert.notNull(connectionFactoryName, "ConnectionFactory name must not be null!");
|
||||
Assert.notNull(connectionFactory, "ConnectionFactory must not be null!");
|
||||
|
||||
this.connectionFactories.put(connectionFactoryName, connectionFactory);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.r2dbc.connectionfactory.lookup.ConnectionFactoryLookup#getConnectionFactory(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public ConnectionFactory getConnectionFactory(String connectionFactoryName)
|
||||
throws ConnectionFactoryLookupFailureException {
|
||||
|
||||
Assert.notNull(connectionFactoryName, "ConnectionFactory name must not be null!");
|
||||
|
||||
ConnectionFactory connectionFactory = this.connectionFactories.get(connectionFactoryName);
|
||||
|
||||
if (connectionFactory == null) {
|
||||
throw new ConnectionFactoryLookupFailureException(
|
||||
"No ConnectionFactory with name '" + connectionFactoryName + "' registered");
|
||||
}
|
||||
|
||||
return connectionFactory;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2019 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
|
||||
*
|
||||
* https://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.data.r2dbc.connectionfactory.lookup;
|
||||
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An implementation of {@link ConnectionFactoryLookup} that simply wraps a single given {@link ConnectionFactory},
|
||||
* returned for any connection factory name.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class SingleConnectionFactoryLookup implements ConnectionFactoryLookup {
|
||||
|
||||
private final ConnectionFactory connectionFactory;
|
||||
|
||||
/**
|
||||
* Create a new instance of the {@link SingleConnectionFactoryLookup} class.
|
||||
*
|
||||
* @param connectionFactory the single {@link ConnectionFactory} to wrap.
|
||||
*/
|
||||
public SingleConnectionFactoryLookup(ConnectionFactory connectionFactory) {
|
||||
|
||||
Assert.notNull(connectionFactory, "ConnectionFactory must not be null!");
|
||||
|
||||
this.connectionFactory = connectionFactory;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.r2dbc.connectionfactory.lookup.ConnectionFactoryLookup#getConnectionFactory(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public ConnectionFactory getConnectionFactory(String connectionFactoryName)
|
||||
throws ConnectionFactoryLookupFailureException {
|
||||
return this.connectionFactory;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Provides a strategy for looking up R2DBC ConnectionFactories by name.
|
||||
*/
|
||||
@org.springframework.lang.NonNullApi
|
||||
@org.springframework.lang.NonNullFields
|
||||
package org.springframework.data.r2dbc.connectionfactory.lookup;
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright 2019 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
|
||||
*
|
||||
* https://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.data.r2dbc.connectionfactory.lookup;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
import reactor.util.context.Context;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link AbstractRoutingConnectionFactory}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class AbstractRoutingConnectionFactoryUnitTests {
|
||||
|
||||
private static final String ROUTING_KEY = "routingKey";
|
||||
|
||||
@Mock ConnectionFactory defaultConnectionFactory;
|
||||
@Mock ConnectionFactory routedConnectionFactory;
|
||||
|
||||
DummyRoutingConnectionFactory sut;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
|
||||
sut = new DummyRoutingConnectionFactory();
|
||||
sut.setDefaultTargetConnectionFactory(defaultConnectionFactory);
|
||||
}
|
||||
|
||||
@Test // gh-98
|
||||
public void shouldDetermineRoutedFactory() {
|
||||
|
||||
sut.setTargetConnectionFactories(Collections.singletonMap("key", routedConnectionFactory));
|
||||
sut.setConnectionFactoryLookup(new MapConnectionFactoryLookup());
|
||||
sut.afterPropertiesSet();
|
||||
|
||||
sut.determineTargetConnectionFactory() //
|
||||
.subscriberContext(Context.of(ROUTING_KEY, "key")) //
|
||||
.as(StepVerifier::create) //
|
||||
.expectNext(routedConnectionFactory) //
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test // gh-98
|
||||
public void shouldFallbackToDefaultConnectionFactory() {
|
||||
|
||||
sut.setTargetConnectionFactories(Collections.singletonMap("key", routedConnectionFactory));
|
||||
sut.afterPropertiesSet();
|
||||
|
||||
sut.determineTargetConnectionFactory() //
|
||||
.as(StepVerifier::create) //
|
||||
.expectNext(defaultConnectionFactory) //
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test // gh-98
|
||||
public void initializationShouldFailUnsupportedLookupKey() {
|
||||
|
||||
sut.setTargetConnectionFactories(Collections.singletonMap("key", new Object()));
|
||||
|
||||
assertThatThrownBy(() -> sut.afterPropertiesSet()).isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@Test // gh-98
|
||||
public void initializationShouldFailUnresolvableKey() {
|
||||
|
||||
sut.setTargetConnectionFactories(Collections.singletonMap("key", "value"));
|
||||
sut.setConnectionFactoryLookup(new MapConnectionFactoryLookup());
|
||||
|
||||
assertThatThrownBy(() -> sut.afterPropertiesSet()).isInstanceOf(ConnectionFactoryLookupFailureException.class)
|
||||
.hasMessageContaining("No ConnectionFactory with name 'value' registered");
|
||||
}
|
||||
|
||||
@Test // gh-98
|
||||
public void unresolvableConnectionFactoryRetrievalShouldFail() {
|
||||
|
||||
sut.setLenientFallback(false);
|
||||
sut.setConnectionFactoryLookup(new MapConnectionFactoryLookup());
|
||||
sut.setTargetConnectionFactories(Collections.singletonMap("key", routedConnectionFactory));
|
||||
sut.afterPropertiesSet();
|
||||
|
||||
sut.determineTargetConnectionFactory() //
|
||||
.subscriberContext(Context.of(ROUTING_KEY, "unknown")) //
|
||||
.as(StepVerifier::create) //
|
||||
.verifyError(IllegalStateException.class);
|
||||
}
|
||||
|
||||
@Test // gh-98
|
||||
public void connectionFactoryRetrievalWithUnknownLookupKeyShouldReturnDefaultConnectionFactory() {
|
||||
|
||||
sut.setTargetConnectionFactories(Collections.singletonMap("key", routedConnectionFactory));
|
||||
sut.setDefaultTargetConnectionFactory(defaultConnectionFactory);
|
||||
sut.afterPropertiesSet();
|
||||
|
||||
sut.determineTargetConnectionFactory() //
|
||||
.subscriberContext(Context.of(ROUTING_KEY, "unknown")) //
|
||||
.as(StepVerifier::create) //
|
||||
.expectNext(defaultConnectionFactory) //
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test // gh-98
|
||||
public void connectionFactoryRetrievalWithoutLookupKeyShouldReturnDefaultConnectionFactory() {
|
||||
|
||||
sut.setTargetConnectionFactories(Collections.singletonMap("key", routedConnectionFactory));
|
||||
sut.setDefaultTargetConnectionFactory(defaultConnectionFactory);
|
||||
sut.setLenientFallback(false);
|
||||
sut.afterPropertiesSet();
|
||||
|
||||
sut.determineTargetConnectionFactory() //
|
||||
.as(StepVerifier::create) //
|
||||
.expectNext(defaultConnectionFactory) //
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test // gh-98
|
||||
public void shouldLookupFromMap() {
|
||||
|
||||
MapConnectionFactoryLookup lookup = new MapConnectionFactoryLookup("lookup-key", routedConnectionFactory);
|
||||
|
||||
sut.setConnectionFactoryLookup(lookup);
|
||||
sut.setTargetConnectionFactories(Collections.singletonMap("my-key", "lookup-key"));
|
||||
sut.afterPropertiesSet();
|
||||
|
||||
sut.determineTargetConnectionFactory() //
|
||||
.subscriberContext(Context.of(ROUTING_KEY, "my-key")) //
|
||||
.as(StepVerifier::create) //
|
||||
.expectNext(routedConnectionFactory) //
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test // gh-98
|
||||
@SuppressWarnings("unchecked")
|
||||
public void shouldAllowModificationsAfterInitialization() {
|
||||
|
||||
MapConnectionFactoryLookup lookup = new MapConnectionFactoryLookup();
|
||||
|
||||
sut.setConnectionFactoryLookup(lookup);
|
||||
sut.setTargetConnectionFactories((Map) lookup.getConnectionFactories());
|
||||
sut.afterPropertiesSet();
|
||||
|
||||
sut.determineTargetConnectionFactory() //
|
||||
.subscriberContext(Context.of(ROUTING_KEY, "lookup-key")) //
|
||||
.as(StepVerifier::create) //
|
||||
.expectNext(defaultConnectionFactory) //
|
||||
.verifyComplete();
|
||||
|
||||
lookup.addConnectionFactory("lookup-key", routedConnectionFactory);
|
||||
sut.afterPropertiesSet();
|
||||
|
||||
sut.determineTargetConnectionFactory() //
|
||||
.subscriberContext(Context.of(ROUTING_KEY, "lookup-key")) //
|
||||
.as(StepVerifier::create) //
|
||||
.expectNext(routedConnectionFactory) //
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
static class DummyRoutingConnectionFactory extends AbstractRoutingConnectionFactory {
|
||||
|
||||
@Override
|
||||
protected Mono<Object> determineCurrentLookupKey() {
|
||||
return Mono.subscriberContext().filter(it -> it.hasKey(ROUTING_KEY)).map(it -> it.get(ROUTING_KEY));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2019 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
|
||||
*
|
||||
* https://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.data.r2dbc.connectionfactory.lookup;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanNotOfRequiredTypeException;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link BeanFactoryConnectionFactoryLookup}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class BeanFactoryConnectionFactoryLookupUnitTests {
|
||||
|
||||
private static final String CONNECTION_FACTORY_BEAN_NAME = "connectionFactory";
|
||||
|
||||
@Mock BeanFactory beanFactory;
|
||||
|
||||
@Test // gh-98
|
||||
public void shouldLookupConnectionFactory() {
|
||||
|
||||
DummyConnectionFactory expectedConnectionFactory = new DummyConnectionFactory();
|
||||
when(beanFactory.getBean(CONNECTION_FACTORY_BEAN_NAME, ConnectionFactory.class))
|
||||
.thenReturn(expectedConnectionFactory);
|
||||
|
||||
BeanFactoryConnectionFactoryLookup lookup = new BeanFactoryConnectionFactoryLookup();
|
||||
lookup.setBeanFactory(beanFactory);
|
||||
ConnectionFactory connectionFactory = lookup.getConnectionFactory(CONNECTION_FACTORY_BEAN_NAME);
|
||||
|
||||
assertThat(connectionFactory).isNotNull();
|
||||
assertThat(connectionFactory).isSameAs(expectedConnectionFactory);
|
||||
}
|
||||
|
||||
@Test // gh-98
|
||||
public void shouldLookupWhereBeanFactoryYieldsNonConnectionFactoryType() {
|
||||
|
||||
BeanFactory beanFactory = mock(BeanFactory.class);
|
||||
|
||||
when(beanFactory.getBean(CONNECTION_FACTORY_BEAN_NAME, ConnectionFactory.class)).thenThrow(
|
||||
new BeanNotOfRequiredTypeException(CONNECTION_FACTORY_BEAN_NAME, ConnectionFactory.class, String.class));
|
||||
|
||||
BeanFactoryConnectionFactoryLookup lookup = new BeanFactoryConnectionFactoryLookup(beanFactory);
|
||||
|
||||
assertThatExceptionOfType(ConnectionFactoryLookupFailureException.class)
|
||||
.isThrownBy(() -> lookup.getConnectionFactory(CONNECTION_FACTORY_BEAN_NAME));
|
||||
}
|
||||
|
||||
@Test // gh-98
|
||||
public void shouldLookupWhereBeanFactoryHasNotBeenSupplied() {
|
||||
|
||||
BeanFactoryConnectionFactoryLookup lookup = new BeanFactoryConnectionFactoryLookup();
|
||||
|
||||
assertThatThrownBy(() -> lookup.getConnectionFactory(CONNECTION_FACTORY_BEAN_NAME))
|
||||
.isInstanceOf(IllegalStateException.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2019 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
|
||||
*
|
||||
* https://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.data.r2dbc.connectionfactory.lookup;
|
||||
|
||||
import io.r2dbc.spi.Connection;
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
import io.r2dbc.spi.ConnectionFactoryMetadata;
|
||||
|
||||
import org.reactivestreams.Publisher;
|
||||
|
||||
/**
|
||||
* Stub, do-nothing {@link ConnectionFactory} implementation.
|
||||
* <p>
|
||||
* All methods throw {@link UnsupportedOperationException}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class DummyConnectionFactory implements ConnectionFactory {
|
||||
|
||||
@Override
|
||||
public Publisher<? extends Connection> create() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectionFactoryMetadata getMetadata() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2019 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
|
||||
*
|
||||
* https://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.data.r2dbc.connectionfactory.lookup;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link MapConnectionFactoryLookup}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class MapConnectionFactoryLookupUnitTests {
|
||||
|
||||
private static final String CONNECTION_FACTORY_NAME = "connectionFactory";
|
||||
|
||||
@Test // gh-98
|
||||
public void getConnectionFactorysReturnsUnmodifiableMap() {
|
||||
|
||||
MapConnectionFactoryLookup lookup = new MapConnectionFactoryLookup();
|
||||
Map<String, ConnectionFactory> connectionFactories = lookup.getConnectionFactories();
|
||||
|
||||
assertThatThrownBy(() -> connectionFactories.put("", new DummyConnectionFactory()))
|
||||
.isInstanceOf(UnsupportedOperationException.class);
|
||||
}
|
||||
|
||||
@Test // gh-98
|
||||
public void shouldLookupConnectionFactory() {
|
||||
|
||||
Map<String, ConnectionFactory> connectionFactories = new HashMap<>();
|
||||
DummyConnectionFactory expectedConnectionFactory = new DummyConnectionFactory();
|
||||
|
||||
connectionFactories.put(CONNECTION_FACTORY_NAME, expectedConnectionFactory);
|
||||
MapConnectionFactoryLookup lookup = new MapConnectionFactoryLookup();
|
||||
|
||||
lookup.setConnectionFactories(connectionFactories);
|
||||
|
||||
ConnectionFactory connectionFactory = lookup.getConnectionFactory(CONNECTION_FACTORY_NAME);
|
||||
|
||||
assertThat(connectionFactory).isNotNull();
|
||||
assertThat(connectionFactory).isSameAs(expectedConnectionFactory);
|
||||
}
|
||||
|
||||
@Test // gh-98
|
||||
public void addingConnectionFactoryPermitsOverride() {
|
||||
|
||||
Map<String, ConnectionFactory> connectionFactories = new HashMap<>();
|
||||
DummyConnectionFactory overriddenConnectionFactory = new DummyConnectionFactory();
|
||||
DummyConnectionFactory expectedConnectionFactory = new DummyConnectionFactory();
|
||||
connectionFactories.put(CONNECTION_FACTORY_NAME, overriddenConnectionFactory);
|
||||
|
||||
MapConnectionFactoryLookup lookup = new MapConnectionFactoryLookup();
|
||||
|
||||
lookup.setConnectionFactories(connectionFactories);
|
||||
lookup.addConnectionFactory(CONNECTION_FACTORY_NAME, expectedConnectionFactory);
|
||||
|
||||
ConnectionFactory connectionFactory = lookup.getConnectionFactory(CONNECTION_FACTORY_NAME);
|
||||
|
||||
assertThat(connectionFactory).isNotNull();
|
||||
assertThat(connectionFactory).isSameAs(expectedConnectionFactory);
|
||||
}
|
||||
|
||||
@Test // gh-98
|
||||
@SuppressWarnings("unchecked")
|
||||
public void getConnectionFactoryWhereSuppliedMapHasNonConnectionFactoryTypeUnderSpecifiedKey() {
|
||||
|
||||
Map connectionFactories = new HashMap<>();
|
||||
connectionFactories.put(CONNECTION_FACTORY_NAME, new Object());
|
||||
MapConnectionFactoryLookup lookup = new MapConnectionFactoryLookup(connectionFactories);
|
||||
|
||||
assertThatThrownBy(() -> lookup.getConnectionFactory(CONNECTION_FACTORY_NAME))
|
||||
.isInstanceOf(ClassCastException.class);
|
||||
}
|
||||
|
||||
@Test // gh-98
|
||||
public void getConnectionFactoryWhereSuppliedMapHasNoEntryForSpecifiedKey() {
|
||||
|
||||
MapConnectionFactoryLookup lookup = new MapConnectionFactoryLookup();
|
||||
|
||||
assertThatThrownBy(() -> lookup.getConnectionFactory(CONNECTION_FACTORY_NAME))
|
||||
.isInstanceOf(ConnectionFactoryLookupFailureException.class);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user