How do I control spring injections that vary between the test environment and the production environment? - spring

I'm setting up a CI situation in which I will deploy my web app to a test environment. In this test environment, I want the business objects used by the app to be mocks of the real ones; the mocks will return static test data. I'm using this to run tests agains my ui. I'm controlling the injections of these business object dependencies with Spring; it's a struts 2 application, for what that's worth.
My question is Maven related, I think. What is the best way to have my Maven build determine whether or not to build the spring configuration out for injecting the mocks or injecting the real thing? Is this a good use for maven profiles? Other alternatives?

Spring itself has support for profiles (if you're using 3.1 or newer), for a web-application you can use context-parameter to set the active profile for different environments in the web.xml:
<context-param>
<param-name>spring.profiles.default</param-name>
<param-value>test</param-value>
</context-param>
Edit: For Maven & Jenkins, you should be able to set the parameter for a build job as follows:
First, let Maven filter your xml-resources (in this example, only files ending with xml are filtered, others are included without filtering) by adding the following into your pom.xml inside the <build> </build> -tags:
<resources>
<resource>
<directory>src/main/webapp</directory>
<filtering>true</filtering>
<includes>
<include>**/*xml</include>
</includes>
</resource>
<resource>
<directory>src/main/webapp</directory>
<filtering>false</filtering>
<excludes>
<exclude>**/*xml</exclude>
</excludes>
</resource>
</resources>
Then, parameterize the context-param in your web.xml:
<context-param>
<param-name>spring.profiles.default</param-name>
<param-value>${env.SPRINGPROFILE}</param-value>
</context-param>
Then parameterize the build job in Jenkins to set the desired string parameter for SPRINGPROFILE (for example test or prod): https://wiki.jenkins-ci.org/display/JENKINS/Parameterized+Build

It's probably a bad idea to do anything with the build of the web app artifact ( Maven best practice for generating artifacts for multiple environments [prod, test, dev] with CI/Hudson support? ). While you could use various mechanisms to produce a WAR file with different configurations of the Spring injections for different contexts, the WAR artifact should be the same every time it's built.
In order to extract the configuration out of the WAR, I have used Spring 3's ability to pull in override values from an external property file. I define default, i.e. produciton, values of my business objects. And I configure spring to check for the existence of a properties file, something I will deploy when the app is in a testing environment and requires mock injections. If that properties file exists, it's values are injected instead. Here's the relevent bit of the spring config file.
<!-- These are the default values -->
<util:properties id="defaultBeanClasses">
<prop key="myManagerA">com.myco.ManagerAImpl</prop>
<prop key="myManagerB">com.myco.ManagerBImpl</prop>
</util:properties>
<!-- Pull in the mock overrides if they exist. -->
<context:property-placeholder
location="file:///my/location/mockBeans.properties"
ignore-resource-not-found="true"
properties-ref="defaultBeanClasses"/>
<!-- The beans themselves. -->
<bean id="managerA" class="${myManagerA}"/>
<bean id="managerB" class="${myManagerB}"/>
And here is the contents of the external "mockBeans.properties" file:
#Define mock implementations for core managers
myManagerA=com.myco.ManagerAMockImpl
myManagerB=com.myco.ManagerBMockImpl
This works nicely. You can even include the mockBeans.properties file in the actual WAR, if you like, but not in the live location. Then the test environment task would be too move it to the location pointed at by the spring config. Alternatively, you could have the mock properties reside in a completely different project.

Related

Spring boot tests - run tests 2 time with different application-xxx.properties each time

I have a spring boot app that has tests for database stuff and I'm supporting mysql and mssql.
I have src/text/resources/application-mysql.properties and src/text/resources/application-mssql.properties
What environment variable can I set when I run my tests to tell Spring which test properties file to use?
Property files in the format application-*.properties are activated using Spring Profiles. Same thing for YAML files, by the way! It is important to know that application.properties is still loaded first and any profile-specific properties will overwrite previously loaded properties (kind of the whole point of Spring Profiles).
There are multiple ways to enable profiles:
To answer your question, you can set the SPRING_PROFILES_ACTIVE environment variable to enable profiles. For example, export SPRING_PROFILES_ACTIVE=mysql. You can also specify multiple profiles (and they are loaded in the same order) by separating them with a comma: export SPRING_PROFILES_ACTIVE=localdefaults,local.
You can also use the JVM parameter, spring.profiles.active. The value follows the same format as that of the environment variable. For example, -Dspring.profiles.active=mysql.
You can use the #ActiveProfiles annotation on your test class. For example:
// Other annotations...
#ActiveProfiles("mysql")
public class MyTest {
If you want to enable profiles during a build, you can set the spring.profiles.active property in Maven. For example:
<profiles>
<profile>
<id>mysql</id>
<properties>
<spring.profiles.active>mysql</spring.profiles.active>
</properties>
</profile>
...
</profiles>
Here's a weird one I recently learned. You can also set active profiles with the spring.profiles.active in a properties file. I imagine this has its uses, but have never used this approach.
Read more about everything I have covered:
https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto.properties-and-configuration
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/test/context/ActiveProfiles.html

Integrate Activiti Modeler using Maven

How one can integrate Activiti Modeler into their own web application and keep all the advantages Maven suggests?
The probem is that Activiti Modeler in Maven is part of Activiti Explorer. There are several questions online from people who want to develop their own web applications, use Modeler to edit the processes, but don't need other Explorer features.
For example, Activiti BPM without activiti-explorer or How To Integrate Activiti Modeller Into own Web Application
I have managed to do this using Maven overlay feature:
1) include overlay of Explorer web app, but include only the Modeler files:
pom.xml:
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-webapp-explorer2</artifactId>
<version>${activiti-version}</version>
<type>war</type>
<scope>compile</scope>
</dependency>
....
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<overlays>
<overlay>
<groupId>org.activiti</groupId>
<artifactId>activiti-webapp-explorer2</artifactId>
<includes>
<include>WEB-INF/classes/stencilset.json</include>
<include>editor-app/**</include>
<include>modeler.html</include>
</includes>
</overlay>
</overlays>
</configuration>
</plugin>
2) add modeler Spring resources. They are used to retrieve and to save models (note: not process definitions, it's kinda different thing) and also to serve the stencilset:
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-modeler</artifactId>
<version>${activiti-version}</version>
</dependency>
3) that would be it but it won't actually work in your application unless it is called "activiti-explorer". Add a file to your project called "editor-app/app-cfg.js", and add the following content there:
editor-app/app-cfg.js:
'use strict';
var ACTIVITI = ACTIVITI || {};
ACTIVITI.CONFIG = {
'contextRoot' : window.location.pathname.substring(0,window.location.pathname.lastIndexOf('/')),
};
This is actually a copy of the native app-cfg, which contains the strange "/activiti-explorer/service" setting for context root. We change it to more generic setting. It will be used to retrieve models from the repository. Our file will overlay the one that ships with explorer webapp.
Notes:
a) you have to manage conversion of process definitions to models by yourselves. For an idea, see https://github.com/Activiti/Activiti/blob/activiti-5.19.0.1/modules/activiti-explorer/src/main/java/org/activiti/editor/ui/ConvertProcessDefinitionPopupWindow.java
b) I had to avoid using one Jackson Object Mapper for everything, I haven't research why this didn't work:
<bean id="objectMapper" class="com.fasterxml.jackson.databind.ObjectMapper">
</bean>
<mvc:annotation-driven>
<!-- using the same objectMapper leads to stencilset resource being served as string -->
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper" ref="objectMapper"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
Don't do this or research more, as this actually breaks the stencilcet resurce serving part of the "activiti-modeler". It starts serving stencilset as a malformed string instead normal json.
c) I had no idea how to inject CSRF security headers in the Modeler saving function, so I switched it off - if you don't use Spring Security, discard this

How to pass value to maven pom.xml at rum time from java file?

I have a java file where a variable taken value at run time.I search for a service using web service discovery and keep its url in a variable.
Now I need to pass this value to pom.xml.
abc.java has code with
String url= http://xx.xx.xx.xx:55939/ABCDevice?wsdl
Pom.xml is:
<wsdlOptions>
<wsdlOption>
<wsdl>url</wsdl> <!-- get urlvalue from java file -->
<wsdlLocation>classpath:com/admin/discovery/ABCService.wsdl
</wsdlLocation>
</wsdlOption>
</wsdlOptions>
In wsdl i want to pass string value "http://xx.xx.xx.xx:55939/ABCDevice?wsdl" which is determined only after run time.
How can i do so ?
I don't consider this as an Apache Maven specific issue, but a general Java issue (Maven probably made you aware of it).
During build-time you have no idea what the url should be. Depending on the type of application you have several options:
JNDI (in case of a webcontainer)
A properties file on a predefined location
System properties
As arguments (in case of executable jar)
Adjust web.xml before deploying (some webcontainers can help you with this)
...
In you use a framework like Spring there are easy ways to inject one the options above.

Switching spring application context or Impl java classes using maven profiles

I know the question I'm asking must be answered somewhere but I cant find an example on the net with some guidelines.
I wish to swap out the Spring 3.0 bean definition at build and runtime for a common codebase. I'm also using Maven profiles to build different versions of the same code.
Currently my bean def is
<bean id="somebean" class="com.x.SomeImpl" >
I will need to replace and deploy it at some times as
<bean id="somebean" class="com.x.SomeOtherImpl" >
Now the approaches I'm thinking of are
1) Use Maven profiles to switch out the complete applicationContext.xml to some other applicationContextB.xml based on the Maven profile.
2) Use Maven profiles to somehow? replace only the bean id definition for "somebean"
My questions are:
a) How can Option 2 be achieved?
b) These approaches still compile and package both SomeImpl and SomeOtherImpl during build. How can I pick only one and not the other for compliation and packaging into EAR?
I know Spring 3.1 has env profiles for the beans, but presently that's not an option.
You could consider using the maven resources and filtering feature available. You could have placeholders in your context file and a property file per profile holding values. In each profile, you could use a different property file and appropriately have your context file filtered.
Take a look to Maven Build Helper Plugin add-source.
You can combine profiles and Build Helper Plugin (add-source goal) to add the required classes in both cases.
you can import multiple config files to your config like this:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<import resource="applicationContextA.xml"/>
<import resource="applicationContextB"/>
</beans>
For switching you can use Spring profiles.

Loading a partial Spring context

I am not much of a Spring expert, but was given a legacy system with a huge context file (not separated into modules).
I want to add some unit tests - that validates different parts of the system, with the actual production configuration.
I started using the ClassPathXmlApplicationContext/FileSystemXmlApplicationContext classes to load the context, however - that takes forever.
Is it possible to load only parts of the context file (recursively) without the need to separate the original file into modules?
Update:
I'll just post here my implementation of Ralph's solution using maven:
my pom.xml:
<plugin>
<groupId>com.google.code.maven-config-processor-plugin</groupId>
<artifactId>maven-config-processor-plugin</artifactId>
<version>2.0</version>
<configuration>
<namespaceContexts>
<s>http://www.springframework.org/schema/beans</s>
</namespaceContexts>
<transformations>
<transformation>
<input>context.xml</input>
<output>context-test.xml</output>
<config>test-context-transformation.xml</config>
</transformation>
</transformations>
</configuration>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
<phase>test</phase>
</execution>
</executions>
</plugin>
my test-context-transformation.xml:
<processor>
<add>
<name>/s:beans</name>
<value>
<![CDATA[
default-lazy-init="true"
]]>
</value>
</add>
</processor>
If you are trying to run "unit" tests, you will not require the full application context at all. Just instantiate the class you want to test (and maybe its collaborators, though mocking may be a better option) and off you go. Unit tests should concentrate on single components in isolation - otherwise they are not unit tests.
If you are trying to run a full integration test by creating the complete object hierarchy defined in your application context, then it may be easiest by first refactoring your context and splitting it into modules - as you were suggesting already.
I guess it does not work out of the box. But you can try this (it is just an idea, I don't know if it works)
Spring support so called lazy initialization the idea is to add this to all the beans.
I can imagine two ways.
A simple tool that create an copy of the orignal configuration xml file and add default-lazy-init="true" the container level beans (with s) declaration.
Try do do it programmatic. With a Bean Post Processor, or try to "inject" the default-lazy-init="true" configuration programmatic

Resources