Package io.mats3.spring.jms.factories
Class ScenarioConnectionFactoryProducer
java.lang.Object
io.mats3.spring.jms.factories.ScenarioConnectionFactoryProducer
- All Implemented Interfaces:
MatsProfiles
Provides a factory for a Spring-integrated Wrapper/Facade around a JMS ConnectionFactory, which in addition to
supporting the production setup, also facilitates the development situation where you often want to run against
either an in-vm MQ Broker or against a MQ Broker running on localhost, and also integrates with the
"mats-spring-test" integration test library where when run with the
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. (ActiveMQ is default, but this class by default
employs the MatsTestBroker
tool class for creating these connections, and this class can be directed to
instead create, or connect to, an Artemis broker).
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):
- Production / External Broker (any production-like environments, e.g. Staging/Pre-prod): This is the standard/regular situation for a MQ-based application or service: Connect to the common external production or staging MQ Broker that all other services and their Mats endpoints connect to. (Note that for the scenarios taken into account by this mechanism, all "external environments" (i.e. "production-like") are considered the same. However, you will most probably want the URLs to the external MQ Broker to be different between production and staging and any other such environment. Such switching must be handled by another mechanism.)
- Localhost development, where you are developing on one project employing Mats Endpoints, but also run this project's required collaborating projects/services with their Mats Endpoints on your local development box (typically running the project you currently develop on directly in the IDE, while the other can either run in IDE or on command line): Connect to a MQ Broker that you've fired up on your local development box, i.e. localhost, which the other services running locally also connects to.
- Local-VM development, where you just want to run the service alone, probably with some of the other collaborating Mats Endpoints from other projects/services mocked up in the same project: Connect to an in-vm MQ Broker. An important thing to ensure here is that these mocks, which by definition resides on the same classpath, must NOT end up running in the production environment! - preferably such mocks should not even be included in the production artifact.
- Local-VM integration testing, where you have integration tests either utilizing the full app config with overwriting of certain beans/endpoints using "Remock" or @MockBean, and mocking out collaborating Mats Endpoints from other projects/services; or piece together the required beans/endpoints using e.g. @Import and mocking out other endpoints: Connect to an in-vm MQ Broker.
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.-
Field Summary
Fields inherited from interface io.mats3.spring.jms.factories.MatsProfiles
PROFILE_MATS_LOCALHOST, PROFILE_MATS_LOCALVM, PROFILE_MATS_MOCKS, PROFILE_MATS_REGULAR, PROFILE_MATS_TEST, PROFILE_PRODUCTION, PROFILE_STAGING
-
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionbuild()
SOFT DEPRECATED, usecreateConnectionFactory()
!Creates the appropriateConnectionFactory
, which is a wrapper integrating with Spring - the decision between the configured scenarios is done after all Spring beans are defined.withDefaultScenario
(MatsScenario defaultScenario) Very optional: If you do not explicitly set theScenarioConnectionFactoryWrapper.ScenarioDecider
using thewithScenarioDecider(ScenarioDecider)
method, you get a defaultConfigurableScenarioDecider.createDefaultScenarioDecider()
.withLocalhostConnectionFactory
(ScenarioConnectionFactoryWrapper.ConnectionFactoryProvider localhostConnectionFactoryProvider) Optional: Provide a ConnectionFactoryProvider lambda for theLOCALHOST
scenario (which only is meant to be used for development and possibly testing).withLocalVmConnectionFactory
(ScenarioConnectionFactoryWrapper.ConnectionFactoryProvider localVmConnectionFactoryProvider) Very optional: Provide a ConnectionFactoryProvider lambda for theLOCALVM
scenario (which only is meant to be used for development and testing).withRegularConnectionFactory
(ScenarioConnectionFactoryWrapper.ConnectionFactoryProvider regularConnectionFactoryProvider) Creates aScenarioConnectionFactoryProducer
, where you need to provide theREGULAR
scenario'sScenarioConnectionFactoryWrapper.ConnectionFactoryProvider
.withScenarioDecider
(ScenarioConnectionFactoryWrapper.ScenarioDecider scenarioDecider) Can optionally be overridden should you decide to use a different decision-scheme than thedefault
.
-
Constructor Details
-
ScenarioConnectionFactoryProducer
public ScenarioConnectionFactoryProducer()
-
-
Method Details
-
withRegularConnectionFactory
public static ScenarioConnectionFactoryProducer withRegularConnectionFactory(ScenarioConnectionFactoryWrapper.ConnectionFactoryProvider regularConnectionFactoryProvider) Creates aScenarioConnectionFactoryProducer
, where you need to provide theREGULAR
scenario'sScenarioConnectionFactoryWrapper.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, invokecreateConnectionFactory()
to get theScenarioConnectionFactoryWrapper
that you then can feed to aMatsFactory
. Notice that deciding between Production and e.g. Staging, and other prod-like environments, 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 theLocalVM 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!- Parameters:
regularConnectionFactoryProvider
- a provider for the ConnectionFactory to use in theREGULAR
scenario.- Returns:
- a
ScenarioConnectionFactoryProducer
on which you then optionally can invokewithLocalhostConnectionFactory(ConnectionFactoryProvider)
,withLocalVmConnectionFactory(ConnectionFactoryProvider)
andwithScenarioDecider(ScenarioDecider)
, before invokingcreateConnectionFactory()
.
-
withLocalhostConnectionFactory
public ScenarioConnectionFactoryProducer withLocalhostConnectionFactory(ScenarioConnectionFactoryWrapper.ConnectionFactoryProvider localhostConnectionFactoryProvider) Optional: Provide a ConnectionFactoryProvider lambda for theLOCALHOST
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 default URL"tcp://localhost:61616"
. The tailoring entails DLQ after 1 retry, and 100 ms delay between delivery and the sole redelivery attempt.- Parameters:
localhostConnectionFactoryProvider
- a provider for the ConnectionFactory to use in theLOCALHOST
scenario.- Returns:
this
, for chaining.- See Also:
-
withLocalVmConnectionFactory
public ScenarioConnectionFactoryProducer withLocalVmConnectionFactory(ScenarioConnectionFactoryWrapper.ConnectionFactoryProvider localVmConnectionFactoryProvider) Very optional: Provide a ConnectionFactoryProvider lambda for theLOCALVM
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 ofConnectionFactoryWithStartStopWrapper
, 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!), an instance ofMatsTestBroker
will be gotten by invokingMatsTestBroker.create()
. From the instance ofMatsTestBroker
, theConnectionFactory will be gotten
. Notice that theMatsTestBroker
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 atMatsTestBroker
.- Parameters:
localVmConnectionFactoryProvider
- a provider for the ConnectionFactory to use in theLOCALVM
scenario.- Returns:
this
, for chaining.- See Also:
-
withDefaultScenario
Very optional: If you do not explicitly set theScenarioConnectionFactoryWrapper.ScenarioDecider
using thewithScenarioDecider(ScenarioDecider)
method, you get a defaultConfigurableScenarioDecider.createDefaultScenarioDecider()
. This default is configured to throwIllegalStateException
if none of theMatsScenario
s are chosen. This method can override that by invoking theConfigurableScenarioDecider.setDefaultScenario(Supplier)
method for you. Note: This method is only of use if you employ the default ScenarioDecider, and it thus makes no sense to use it while also employingwithScenarioDecider(ScenarioDecider)
, as you should have handled the default scenario situation in the ScenarioDecider you then provide!- Parameters:
defaultScenario
- whichMatsScenario
should be chosen if theScenarioConnectionFactoryWrapper.ScenarioDecider
does not choose one.- Returns:
this
, for chaining.
-
withScenarioDecider
public ScenarioConnectionFactoryProducer withScenarioDecider(ScenarioConnectionFactoryWrapper.ScenarioDecider scenarioDecider) Can optionally be overridden should you decide to use a different decision-scheme than thedefault
. 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 inMatsTestBroker
, as mentioned in the JavaDoc oflocalVmConnectionFactory(..)
). How you otherwise decide betweenREGULAR
,LOCALHOST
andLOCALVM
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 atwithRegularConnectionFactory(ConnectionFactoryProvider)
. Note: This method should not be used in conjunction with invoking thewithDefaultScenario(MatsScenario)
method, as you should have handled the default scenario situation in the ScenarioDecider you provide!- Parameters:
scenarioDecider
- theScenarioConnectionFactoryWrapper.ScenarioDecider
that should decide between the threeMatsScenario
s.- Returns:
this
, for chaining.
-
build
SOFT DEPRECATED, usecreateConnectionFactory()
! -
createConnectionFactory
Creates the appropriateConnectionFactory
, which is a wrapper integrating with Spring - the decision between the configured scenarios is done after all Spring beans are defined.- Returns:
- the appropriate
ConnectionFactory
, which is a wrapper integrating with Spring.
-