Spring Integration - How to create an optional jms:message-driven-channel-adapter? - spring

I'm looking for a way to conditionally set up jms:message-driven-channel-adapter in spring 3.0 & spring integration 2.2.
I would like to have an entry in a property file like: "create.message.driven.channel.adapter=true" for each environment and I would like spring to decide whether to set up the channel or not based solely on the entry from the property file.
Is there a way to accomplish this using only spring xml configuration and a property file?

You can't do it exactly the way you describe. With Spring 3.1, you could do it with Spring Profiles...
<beans>
...
<beans profile="foo">
<jms:message-driven-adapter ... />
</beans>
</beans>
Then run with ... -Dspring.profiles.active=foo.
You could do it with JavaConfig
#Bean
public Object foo() {
// if property set, return an MDA, otherwise a String
}
Or, probably the easiest, so long as you don't explicitly start() the context, you could use
<jms:message-driven-adapter ...
auto-startup="${start.message.driven.channel.adapter}" />
In which case, the bean would be defined, but it just wouldn't be started so it wouldn't even open a JMS connection. You would also need a property placeholder configurer pointed at your properties file.
But, auto-startup only applies to starting on refresh(), an explicit context.start() will still start it.

Related

Use Spring boot application properties in log4j2.xml

I am working on a web application based on spring boot and want to use log4j2 as the logger implementation.
Everything works fine with the logging configuration defined in a log4j2-spring.xml file.
What is not working: I want to use property placeholders in the log4j2-spring.xml file that should be resolved from properties defined in the application.yml file used for configuring spring boot.
Is this possible? If yes, how?
Direct substitution of properties in log4j2-spring.xml via property placeholder is not possible as the log4j2-spring.xml is outside the ambit of Spring, and used purely for configuration purpose.
However, you can leverage the Log4j2 out-of-box feature of property substitution as outlined here.
Step 1 -
Specify the property name and its variable in log4j2-spring.xml as below
<Configuration status="warn">
<Properties>
<Property name="someProp">${bundle:test:someKey}</Property>
</Properties>
<!--other configs -->
</Configuration>
Step 2 - Use the above defined property in the log configuration e.g. suffix to log file name
<Appenders>
<File name="file" fileName="/path/to/logs/app-${someProp}.log">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p %-40c{1.} - %m%n"/>
</File>
</Appenders>
Step 3 - Create a bundle (viz. properties file) to hold the properties value e.g. test.properties
# properties for log4j2
someKey=someValue
someKey1=someValue1
In your case this file will contain the values in yaml which you seek to use in log4j2 configuration. In case those properties are used in application as well, they will be duplicated in yaml and the bundle (i.e. properties file) which should be acceptable compromise given spring can not inject them in log4j2 configuration.
Let know in comments in case of any more information is required.
I've faced similiar problem with injecting Spring Boot YAML properties into log4j xml configuration, and I found a solution for Spring Boot 1.5.X (and probably 2.0, I didn't test it) which is a little bit hacky and operates on system properties lookup but it certainly works.
Let say you have profile "dev" in your application and some property to inject, then your application-dev.yml looks like this:
property:
toInject: someValue
In your xml configuration log4j2-spring-dev.xml you put something like this:
<Properties>
<property name="someProp">${sys:property.toInject}</property>
</Properties>
Now you have to somehow transfer this spring property to system property. You have to do that after application environment will be prepared and before logging system will initialize. In Spring Boot there is a listener LoggingApplicationListener, which initialize whole logging system and it's triggered by event ApplicationEnvironmentPreparedEvent, so let's create listener with order with higher precedence than LoggingApplicationListener:
public class LoggingListener implements ApplicationListener, Ordered {
#Override
public int getOrder() {
return LoggingApplicationListener.DEFAULT_ORDER - 1;
}
#Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
ConfigurableEnvironment environment = ((ApplicationEnvironmentPreparedEvent) event).getEnvironment();
List<String> activeProfiles = Arrays.asList(environment.getActiveProfiles());
if (!activeProfiles.contains("dev")) {
return;
}
String someProp = environment.getProperty("property.toInject")
validateProperty(someProp);
System.setProperty("property.toInject", someProp);
}
}
Now register this listener in your application:
public static void main(String[] args) {
SpringApplication application = new SpringApplication(MyApplication.class);
application.addListeners(new LoggingListener());
application.run(args);
}
And that's it. Your Spring Boot properties should be "injected" in your log4j2 configuration file. This solution works with classpath properties and --spring.config.location properties. Note, it would not work with with some external configuration system like Spring Cloud Config.
Hope it helps
If you use mvn, you could use the mvn resource plugin. This will let you achieve your goal in build time.
Link: https://maven.apache.org/plugins/maven-resources-plugin/examples/filter.html

Configure Registry in camel context xml

I am new to Apache Camel and I am in a situation where my application needs a codec (HL7) to be registered with camel context. I know there is a solution where you can create a default camel context with an instance of your own registry but is there any way I could configure my own registry in the camel context?
I am using JavaDSL to develop my application and the configuration in context goes like this.
<bean id="hl7codec" class="org.apache.camel.component.hl7.HL7MLLPCodec">
<property name="charset" value="iso-8859-1"/>
</bean>
<camelcontext id = "context">
<ref bean = "MyRouteBuilder"/>
<camelcontext/>
I build the routes in MyRouteBuilder Class by overriding the configure method. My route goes like this.
from("mina2:tcp://localhost:8888?sync=true&codec=#hl7codec").to("jms:queue")
However, the codec doesn't seem to work. When I remove the codec, My application runs just fine and accepts HL7 messages but with the codec, I am not able to receive any messages. I feel this occurs because the codec bean is defined but the context isnt able to pick it up. I do not want to create a defaultcamelcontext with the required registry settings. Rather, I am looking for a way to register the codec within camelcontext configuration xml, and so far, I have failed.
Am I missing anything with my configuration? Any help would be greatly appreciated.
You normally should not need to use & in Java DSL, so replace &codec= with &codec=

Spring customised PropertyPlaceholderConfigurer

I have config xml based spring application for which I have moved proprties required at start up time in database. It was very difficult to manage hundreds in property file and that is why database is introduced. To read properties a spring restful service is developed to return a map of all properties required at start up time.
I want to know how to replace properties reading from a map to spring context file e.g. ${config.service.url} should be polulated from a map read via web service.
One option I considered is to upgrade to Annotation based and start using MapPropertySource and Environment interface as environment.getRequiredProperty("config.service.url"). However upgrading to Annotation based is a big impact on project and is no at this time.
Second option that I am looking forward is to have a customised PropertyPlaceholderConfigurer.
Any pointer/help on this will be great.
Cheers,
Amber
You could define a PropertyPlaceholderConfigurer, but instead of specifying a file location, you can pass the properties directly as returned by your restful service.
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties" .../>
</bean>

How to retrieve context parameters in Spring 3.1 xml context

It seems like there's been a few iterations of property support in spring it's hard to tell what's best practice and the manuals are written from the point of view of someone who is familiar with every other iteration. I feel like this should be a simple and common requirement but given how hard it's been please correct me if there's a more idiomatic way.
What I want is to pass an additional properties file to my spring web app based on a context property which the client is setting using a tomcat descriptor like so
<Context path="/foo" reloadable="true">
<Parameter name="foo.config" value="file:${catalina.base}/conf/foo.properties"/>
</Context>
In spring for the live profile I have this
<beans profile="live">
<context:property-placeholder location="classpath:timetabling.live.properties,${timetabling.config}"
ignore-resource-not-found="true" />
</beans>
So I'd assumed this doesn;t work because I'm trying to configure placeholder suppport with a placeholder. If I use a system property however then this works fine. I know that spring 3.1 has baked in support for system and environment properties so I guess my question is how can I augment this support with something context aware before the placeholder is resolved?
--Update--
looking at http://blog.springsource.org/2011/02/15/spring-3-1-m1-unified-property-management/ particularly at footnote 1, I would expect to have a DefaultWebEnvironment which should already have aceess to context init params. Now I am more confused, can someone provide me with a concrete example of context property retrieval? At this point I feel like I've read every javadoc available and they are just not helpful.
<context:property-placeholder /> sets up a PropertyPlaceholderConfigurer which reads from .properties, system properties and environment variables. A Tomcat context.xml however sets up a servlet context init parameter. So what you need is a ServletContextPropertyPlaceholderConfigurer.

Configuration file changes at runtime for a standalone app?

Say I have a Swing/Spring standalone application. I am wondering whether Spring does detect runtime changes to its configuration file such as this one (assuming the file is on the classpath):
Commenting second bean and adding first bean as below:
<beans>
<bean id="randonNumberGenerator" class="com.me.MyGenerator"/>
<!--
<bean id="randonNumberGenerator" class="com.someoneelse.ADifferentGenerator"/>
-->
</beans>
Will Spring change the implementation at runtime as expected?
I don't think Spring provides a way to reload the configuration on-the-fly. It could be possible by re-instantiating the entire ApplicationContext, but that would mean that all beans are recreated etc., and internal state of the software would probably fly out the window in the process.
I think you can use the "AbstractRefreshableApplicationContext" to refresh the context.
AbstractRefreshableApplicationContext refreshableContext = new ClassPathXmlApplicationContext ( "applicationContextRefreshable.xml" );
refreshableContext.refresh ( );
For details you can have a look here

Resources