public class ScenarioConnectionFactoryProducer extends java.lang.Object implements MatsProfiles
MatsTestProfile
you will most
probably want an in-vm setup (typically mocking up the project-external Mats endpoints that the tested endpoints
collaborate with). In the in-vm broker situations, the JMS ConnectionFactory instantiation lambda you provide for
what will be used in the production setup will not be invoked, but instead an in-vm ActiveMQ Broker will be
started, and an ActiveMQ ConnectionFactory will be produced.
Note: The actual decision logic and "Spring interfacing" is done in ScenarioConnectionFactoryWrapper
, which
is the actual class of instances that will end up as Spring beans - this class is a producer of such instances,
simplifying the configuration, providing sane defaults.
Do note that this is purely a convenience functionality, and is in no way required for the Mats system to work.
As a matter of fact, you can achieve the exact same with Spring's Profiles (or any other "switch configuration based
on some property or state"-logic you can cook up), but this class effectively represents an opinionated
implementation of the config switching that will be needed in most scenarios working with Mats, and will probably
yield less configuration overall. Moreover, Mats will most probably be employed in a micro/multiple service
architecture, and in such situations, it is nice to make some in-house library that constitute basic building blocks
that all the services will need. With that in mind, this class also facilitates so you can easily construct an
@CompanyMatsSetup
-type annotation which alone will pull up both the needed ConnectionFactory (with URL
and whatever needed already set) and MatsFactory, which handles all the mentioned scenarios, by merely placing that
annotation on the main config class of your service.
The point is this: If you are new to Message Queue based development, you will probably soon sit with the problem of how to create a code base that efficiently lets you run it in production, while also is easy to develop on, and being simple to perform integration test on your endpoints - the problem being that you need different types of ConnectionFactories for the different scenarios, and in some cases also needing an in-vm MQ Broker.
There are typically four different scenarios that you need to juggle between, the two latter being identical wrt. the
Mats setup (which is the reason that MatsScenario
only has three scenarios defined):
MatsProfiles
and its enum values!
For the localhost and localVM scenarios, this class by default utilizes the ActiveMQ Broker and ConnectionFactory. For all scenarios, but in particular for the "regular" (production-like), you can provide whatever ConnectionFactory you want (configured as you desire) - this class will just wrap it.
PROFILE_MATS_LOCALHOST, PROFILE_MATS_LOCALVM, PROFILE_MATS_MOCKS, PROFILE_MATS_REGULAR, PROFILE_MATS_TEST, PROFILE_PRODUCTION, PROFILE_STAGING
Constructor and Description |
---|
ScenarioConnectionFactoryProducer() |
Modifier and Type | Method and Description |
---|---|
ScenarioConnectionFactoryWrapper |
build()
Creates the appropriate
ConnectionFactory , which is a wrapper integrating with Spring - the decision
between the configured scenarios is done after all Spring beans are defined. |
ScenarioConnectionFactoryProducer |
withDefaultScenario(MatsScenario defaultScenario)
Very optional: If you do not set the
ScenarioConnectionFactoryWrapper.ScenarioDecider using the
#withScenarioDecider(ScenarioDecider) method, you get a
ConfigurableScenarioDecider.createDefaultScenarioDecider() . |
ScenarioConnectionFactoryProducer |
withLocalhostConnectionFactory(ScenarioConnectionFactoryWrapper.ConnectionFactoryProvider localhostConnectionFactoryProvider)
Optional: Provide a ConnectionFactoryProvider lambda for the
LOCALHOST scenario
(which only is meant to be used for development and possibly testing). |
ScenarioConnectionFactoryProducer |
withLocalVmConnectionFactory(ScenarioConnectionFactoryWrapper.ConnectionFactoryProvider localVmConnectionFactoryProvider)
Very optional: Provide a ConnectionFactoryProvider lambda for the
LOCALVM scenario
(which only is meant to be used for development and testing). |
static ScenarioConnectionFactoryProducer |
withRegularConnectionFactory(ScenarioConnectionFactoryWrapper.ConnectionFactoryProvider regularConnectionFactoryProvider)
Creates a
ScenarioConnectionFactoryProducer , where you need to provide the REGULAR scenario's ScenarioConnectionFactoryWrapper.ConnectionFactoryProvider . |
ScenarioConnectionFactoryProducer |
withScenarioDecider(ScenarioConnectionFactoryWrapper.ScenarioDecider scenarioDecider)
Can optionally be overridden should you decide to use a different decision-scheme than the
default . |
public static ScenarioConnectionFactoryProducer withRegularConnectionFactory(ScenarioConnectionFactoryWrapper.ConnectionFactoryProvider regularConnectionFactoryProvider)
ScenarioConnectionFactoryProducer
, where you need to provide the REGULAR
scenario's ScenarioConnectionFactoryWrapper.ConnectionFactoryProvider
. This is the one that will be used in Production and
Production-like environments, e.g. Staging, Acceptance Testing, Pre-Prod or whatever you call those environments.
You may invoke the other "withXXX" methods to tailor further, but this is optional. After finished setup, invoke
build()
to get the ScenarioConnectionFactoryWrapper
that you then can feed to a
MatsFactory
.
Notice that deciding between Production and e.g. Staging and which corresponding ConnectionFactory URL or even type of ConnectionFactory you should employ here, is up to you: You might be using configuration properties, Spring's Profile concept, System Properties (java cmd line "-D"-properties), or system environment variables - only you know how you differentiate between these environments.
Notice: You are required to set up this provider lambda. However, if you are just setting up your project,
wanting to start writing tests, or otherwise only use the LocalVM scenario
, and thus
will not utilize the "regular" scenario just yet, you could just supply a lambda here that throws e.g. an
IllegalStateException or somesuch - which probably will remind you to fix this before going into production!
regularConnectionFactoryProvider
- a provider for the ConnectionFactory to use in the REGULAR
scenario.ScenarioConnectionFactoryProducer
on which you then optionally can invoke
#withLocalhostConnectionFactory(ConnectionFactoryProvider)
,
#withLocalVmConnectionFactory(ConnectionFactoryProvider)
and
#withScenarioDecider(ScenarioDecider)
, before invoking build()
.public ScenarioConnectionFactoryProducer withLocalhostConnectionFactory(ScenarioConnectionFactoryWrapper.ConnectionFactoryProvider localhostConnectionFactoryProvider)
LOCALHOST
scenario
(which only is meant to be used for development and possibly testing). If this is not provided, it will be a
somewhat specially tailored ActiveMQ ConnectionFactory with the URL "tcp://localhost:61616"
, read
more in the ActiveMQ documentation. The
tailoring entails DLQ after 1 retry, and 100 ms delay between delivery and the sole redelivery attempt.localhostConnectionFactoryProvider
- a provider for the ConnectionFactory to use in the LOCALHOST
scenario.this
, for chaining.public ScenarioConnectionFactoryProducer withLocalVmConnectionFactory(ScenarioConnectionFactoryWrapper.ConnectionFactoryProvider localVmConnectionFactoryProvider)
LOCALVM
scenario
(which only is meant to be used for development and testing). The implementation of the lambda is expected to
return a ConnectionFactory to an in-vm MQ Broker. You probably want to have this ConnectionFactory wrapped in
your own extension of ConnectionFactoryWithStartStopWrapper
, which provide a way to start and stop the
in-vm MQ Broker. If this configuration is not provided (and not having to handle this mess is a big point of this
class, so do not provide this unless you want a different broker entirely!), the class
MatsTestBroker
will be instantiated by invoking
MatsTestBroker.createUniqueInVmActiveMq()
. From the instance of MatsTestBroker
, the
ConnectionFactory will be gotten
.
Notice that the MatsTestBroker
has a small extra feature, where you can have it produce a
ConnectionFactory to localhost or a specific URL instead of the in-vm MQ Broker it otherwise produces, by means
of specifying a special system property ("-D" options) (In this case, it does not create the in-vm MQ Broker
either). The rationale for this extra feature is if you wonder how big a difference it makes to run your tests
against a proper MQ Broker instead of the in-vm and fully non-persistent MQ Broker you by default get. Read
JavaDoc at MatsTestBroker
.
localVmConnectionFactoryProvider
- a provider for the ConnectionFactory to use in the LOCALVM
scenario.this
, for chaining.MatsTestBroker
public ScenarioConnectionFactoryProducer withDefaultScenario(MatsScenario defaultScenario)
ScenarioConnectionFactoryWrapper.ScenarioDecider
using the
#withScenarioDecider(ScenarioDecider)
method, you get a
ConfigurableScenarioDecider.createDefaultScenarioDecider()
. This default is configured to throw
IllegalStateException
if none of the MatsScenario
s are chosen. This method can override that by
invoking the ConfigurableScenarioDecider.setDefaultScenario(Supplier)
method for you.
Note: This should not be used in conjunction with invoking the #withScenarioDecider(ScenarioDecider)
, as
you should have handled the default scenario situation in the ScenarioDecider you provide!defaultScenario
- which MatsScenario
should be chosen if the ScenarioConnectionFactoryWrapper.ScenarioDecider
does not choose one.this
, for chaining.public ScenarioConnectionFactoryProducer withScenarioDecider(ScenarioConnectionFactoryWrapper.ScenarioDecider scenarioDecider)
default
. We need a decision for which
MatsScenario is in effect for this JVM, and you can override the standard here. (Do note that if you want to
run integration tests against a specific Active MQ Broker, e.g. on your localhost, there is already a feature for
that in MatsTestBroker
, as mentioned in the JavaDoc of
localVmConnectionFactory(..)
).
How you otherwise decide between REGULAR
, LOCALHOST
and LOCALVM
is up to you. (For REGULAR, you will again have to decide whether you
are in Production or Staging or whatever, if this e.g. gives different URLs or changes which ConnectionFactory
class to instantiate - read more at #withRegularConnectionFactory(ConnectionFactoryProvider)
.
Note: This method should not be used in conjunction with invoking the withDefaultScenario(MatsScenario)
method, as you should have handled the default scenario situation in the ScenarioDecider you provide!scenarioDecider
- the ScenarioConnectionFactoryWrapper.ScenarioDecider
that should decide between the three MatsScenario
s.this
, for chaining.public ScenarioConnectionFactoryWrapper build()
ConnectionFactory
, which is a wrapper integrating with Spring - the decision
between the configured scenarios is done after all Spring beans are defined.ConnectionFactory
, which is a wrapper integrating with Spring.