This is the core of the lightweight module system for the invesdwin software product line platform. It allows to configure an application on a per module basis. On application startup the bootstrap process collects the configuration snippets and creates a full application context. It also handles the lifecycle of the application (providing hooks for modules) for running and testing it. Tests also benefit from the flexibility of replacing bean instances with stubs, choosing different spring-xmls to be loaded depending on the circumstances and enabling embedded servers (e.g. webserver=jetty, database=h2) on a per test basis via annotations. These embedded servers are themselves modules which are available in separate projects and can be even packaged into distributions for use in production environments where appropriate.
This platform shares some of the goals of spring-boot. In comparison this platform provides the following advantages:
ApplicationContext
per testcase without having to write one spring-xml per case, instead reusing and just selecting which spring-xml-snippets to use (essentially solving Spring-XML-Hell in complex testing scenarios)For more information on the concept and ideas behind this platform you can have a look at this presentation that was made for an earlier version of this platform where Ant+Ivy+Groovy was used for configuration management. Today these concepts got adapted into a new and improved Maven implementation that provides many benefits over the older design while still keeping the same features as before. It was just the case that Maven was not where it is today when this platform first came to life, but a switch was finally made when Maven became more robust and faster.
Releases and snapshots are deployed to this maven repository:
https://invesdwin.de/repo/invesdwin-oss-remote/
Dependency declaration:
<dependency>
<groupId>de.invesdwin</groupId>
<artifactId>invesdwin-context</artifactId>
<version>1.0.3</version><!---project.version.invesdwin-context-parent-->
</dependency>
When setting up modules or distributions it is recommended to make invesdwin-context-parent
the parent pom of your specific module/distribution pom.xml. This provides the following benefits respectively. This enables:
If you setup a product (being a collection of modules and distributions) it is recommended to create an intermediate parent pom so you can define your own additional dependency management and plugin overrides (see the granatasoft-remotelist-parent
example web project here).
Though you are free to roll your own parent pom where you just cherry-pick the parts that you like from the parent pom here, or do everything on your own. If you are just interested in the dependency management you can import this pom as a bill of materials. See the included test projects for some examples of the different ways of referencing invesdwin-context modules with maven.
In order to fully benefit from the module system, you should follow the best practice of modules always having the package type jar
. Only distributions should repackage modules into other package types like war
, ear
, zip
and so on. This allows the highest flexibility in module reuse between different products and various distributions for different customers and target environments.
-Dparams=value
and sets them as system parameters to override existing defaults.ApplicationContext
configuration for the test. The context can be customized via setUpContextLocations(...)
, hooks like IStub, IContextLocation or by just adding annotations like @WebServerTest
to your test (which is an annotation available in invesdwin-context-webserver
that runs an embedded jetty server during tests by providing a stub implementation that checks for this annotation automatically for each test). Other such test annotations are available in other invesdwin projects and their respective modules. You can also activate/deactivate/replace spring beans via setUpContext(TestContext)
to fit your testing requirements.The following lifecycle hooks are available, which can either just be added to a spring bean to be automatically picked up during bootstrap or alternatively registered manually in their respective XyzHookManager
class.
de.invesdwin
is scanned. To extend this for your own packages (e.g. com.mycompany
) you can create your own IBasePackageDefinition
implementation and define it as a service provider inside /META-INF/services/de.invesdwin.context.IBasePackageDefinition
. With this, the bootstrap discovers beans/hooks/services in your packages too./META-INF/services/de.invesdwin.context.beans.hook.IInstrumentationHook
. Just put one or more fully qualified class names there for your hook implementations so they can get picked up during bootstrap. Discovering them via classpath scanning (like the other hooks get discovered) would defeat the purpose, since scanning would load too many classes which won't get instrumented then by your hooks.IBlockingStartupHook
instead, though you should not run endless tasks with that.ApplicationContext
during bootstrap when running in production mode, so they can safely be put into your modules src/main/java
without having to worry about if they are only executed inside of tests. This convention of making modules test-aware also does not require you to add test-jar maven dependencies, which themselves won't get transitive dependencies resolved in Maven and might introduce some unwanted stubs that you only need for testing the actual module itself.MergedContext
gets reinitialized during test execution. Useful to do some cleanup of lock files and such while that happens. First initialization will not be notified here, since IStartupHook
is for that purpose.ApplicationContext
you can collect spring beans before the actual application is bootstrapped. This is a preliminary context with which the MergedContext is built. When integrating the platform into another platform, you have to make sure the static initializers inside this class are called very early during application startup or else the instrumentation will be too late since too many classes have already been loaded by the classloader. The following things are setup here:
IBasePackageDefinition
)src/test/java
directory exists, see ContextProperties.IS_TEST_ENVIRONMENT
)ContextProperties
class):
invesdwin-instrument
or to create additional configuration files that get generated from classpath scanning like a persistence.xml) $HOME/.invesdwin
) where files can be stored that can be accessed by different processes and applications (e.g. to store financial data used by multiple instances of parallel running strategy backtest processes)/META-INF/logback/*logback.xml
, /META-INF/logback/*logback-test.xml
for test overrides and /META-INF/logback/*logback-dist.xml
for distribution/release overrides. Note that the logback-test.xml can be put inside your src/test/java
to only be loaded for your JUnit tests to increase the log level for specific libraries. The logback-dist.xml can be put in your distribution modules src/main/java
to be packaged into your release./META-INF/*.properties
and make them available globally as system properties. You can put machine specific properties in the file ${user.home}/.invesdwin/system.properties
. You can set up developer specific properties that get them loaded during testing in any module by placing a /META-INF/env/${USERNAME}.properties
and defining your specific property overrides there. Distributions of your applications can package a /META-INF/env/distribution.properties
to override the properties for your target customer/environment. Please note that security sensitive information should be configurable in a more sensitive fashion. System properties can be read by any other process. So either tighten up the computers the processes run on or tighten up the application themselves (e.g. when delivering fat-clients to end-customers). Anyway when security is not so much a concern, it can be quite handy for an admin to differentiate process configurations by looking at their system properties via JVisualVM on a server.classpath:
protocol which might be needed to easily setup third party frameworks that only support URI pathsDefaultPlatformInitializer
, just set your customized instance via PlatformInitializerProperties.setInitializer(...)
before any initializers have run. Though this is not the normal deployment case and you should thus only worry about it when you go some uncommon path regarding application integration. Or on the other hand if you just want to change the default directories you can also do that here. Sometimes the overhead might just not be needed in which case you cann call PlatformInitializerProperties.setAllowed(false)
to skip it. An example can be found at: ScriptingWithoutBootstrapMain ApplicationContext
the actual application runs after it was bootstrapped. The bootstrap is invoked by the first call of MergedContext.autowire(...)
which is automatically invoked by AMain
or ATest
application entry points. Note that you can also call this method manually in your objects (which are not @Configurable
or spring beans) to get dependency injection. Also you can provide ApplicationContexts
to set them as children of the MergedContext
(can be wrapped in DirectChildContext
and ParentContext
to change the handling) to create a ApplicationContext
hierarchy for special framework integration needs. The bootstrap itself accomplishes the following things:
IContextLocations
that are supposed to build the final ApplicationContext
@Configurable
, @Transactional
, @Scheduled
, @Cacheable
, @Async
so that your beans can utilize them easily/META-INF/xsd/*.xsd
to setup the JAXB validation context properly for use in the Marshaller util inside invesdwin-context-integration
(when that module is in the classpath)log/error.log
and a shortened stacktrace on the console and inside log/common.log
.%s
style text placeholders like one is used from String.format(...)
instead of the SLF4J {}
. Sometimes it is hard to know where one should use which notations, so for invesdwin we settled on %s
and make sure all our utilities recognize that notation. Nothing is worse than a broken log statement when you want to troubleshoot some hairy production problem, so we try everything to minimize these common coding errors.${PROPERTYNAME}
notation. This bean also allows you to set additional context dependant system properties from inside your spring-xml (which can be loaded depending on some logic via IContextLocation
).For applications that also rely on IO (Input/Output of files and streams) and IPC (Inter-Process-Communication), the invesdwin-context-integration
module provides a few tools that make the life easier here. It integrates spring-integration which is an optional framework with which you can build a pipes and filters architecture for your integration workflow. Other invesdwin integration modules extend this to provide support for JMS, AMPQ, REST, WebServices, Spring-Batch, Hadoop and so on. This module though only provides the core functionality:
log/integration.log
. You can disable this for improved performance by changing the loglevel for de.invesdwin.MESSAGES
in your logback config. The MessageLoggingAspect
intercepts all spring-integration @Gateway
and @ServiceActivator
beans, so there is no need for you to figure out how to get those messages.ARetryingCallable
) depending on the exception that was thrown. If some IO or communication related exception is encountered, the method call is retried with a default backoff policy. You can also throw RetryLaterException
or RetryLaterRuntimeException
inside your method to decide for a retry on some other exception or condition.onBeforeRetry(...)
) or do additional retry logic, like sending out an email to an administrator when a system is down or trying to reinitialize some remote service automatically (e.g. when a dynamic service vanished and you have to switch to a different instance which you rediscover from the central service registry). The RetryOriginator
object should provide all meta-information needed to decide about special cases in your retry logic.ABeanCsvReader
, ABeanCsvWriter
and other classes provide some utilities to easily read/write CSV files. This utilizes the popular spring-batch FlatFileItemReader
and Mapper functionality. Though a complete spring-batch integration is found in a different invesdwin integration module.This module packages an embedded jetty server to provide a servlet container for web services and web frameworks either during testing by annotating your test with @WebServerTest
or to deploy your application with a distribution that contains an embedded webserver. You can also call WebserverContextLocation.activate()
/.deactivate()
before the application is bootstrapped to enable/disable the embedded webserver programmatically.
de.invesdwin.context.webserver.Main
or roll your own to add more configuration options.de.invesdwin.context.integration.IntegrationProperties.WEBSERVER_BIND_URI
with its default value http://localhost:9001
is referenced from the invesdwin-context-integration
module to setup the server.
https://
to enable SSL support. Though you should make sure to change the de.invesdwin.context.webserver.WebserverProperties.KEYSTORE_*
properties to switch to a real certificate instead of the auto generated one inside the module itself. Or use the more common approach of setting up a reverse proxy on your apache webserver that adds ssl for your website (see chapter 4.6 from the invesdwin-NoWicket documentation)./META-INF/web/web-fragment.xml
is used to find all module specific web app config snippets. They are then merged to build the actual web.xml configuraton for the webserver. These are not placed in /META-INF/web-fragment.xml
in order to not get automatically picked up when deploying invesdwin modules into a war
archive. In that case the distribution should take care of relocating and merging the files into a web.xml as similarly handled by the fat-jar feature inside the maven-shade-plugin
definition of the invesdwin-context-parent
pom. Otherwise one could not decide to override the automatically generated web.xml with a custom created one in his distribution or to manually disable/rename/reconfigure some services that are shipped with the modules default config.Also note that with this module generally resources are served from the classpath (as this is the only place where modules can store their resources since they are packaged as a jar
). The classpath underlies a resource blacklist that prevents class and java files from being served by accident to ensure security (see BlacklistedWebAppContext
). Also file browsing is disabled on the server for security reasons.
These modules bundle tools and utilities for creating reports of various types:
Aggragating(Ohlc)PointsCollection
: generating charts from large datasets is very slow and memory intensive without having any visual benefit, thus it makes sense to prefilter the data by aggregating points into to-be-pixels. This is handled by this special collection for XY-Points and OHLC-Bars respectively. You normally don't need more than around 10,000 datapoints for a XY-Chart or more than 1,000 datapoints for a OHLC-Chart to look good.AJFreeChartVisitor
: allows to visit and modify chart elements to apply some common modifications on charts by post-processing. The included JFreeChartLocaleChanger
is an example for such a case. It adjusts date and number formats in the chart according to the given locale (JFreeChart otherwise uses the JVM default locale).JFreeChartExporter
: allows you to easily export charts lazily, memory sensitive and in parallel as desired into different file formats and dimensions. It also allows you to scale the fonts via a multiplier so they are not too small on higher chart resolutions.There are a few more modules available in their respective github projects including their individual documentation:
Tips for handling multiple projects and IDE configuration are here. Pull requests are welcome. Direct repo access can be granted upon request.
If you need further assistance or have some ideas for improvements and don't want to create an issue here on github, feel free to start a discussion in our invesdwin-platform mailing list.