metrics-spring configuration via .properties file - java

I'm trying to configure metrics-spring via configuration file
In my spring.xml I've added
<bean id="propertyPlaceholderConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>
classpath:metrics.properties
</value>
</list>
</property>
<property name="systemPropertiesModeName"
value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
<property name="searchSystemEnvironment" value="true"/>
</bean>
filled with something like
metrics.reporter.type=console
and then I'm setting it in the spring config accessing that property via ${metrics.reporter.type}
<metrics:reporter metric-registry="metrics" type="${metrics.reporter.type}" period="1m"/>
During the startup of the web application, spring throws a BeanDefinitionParsingException due to the unresolved variable above
Configuration problem: No ReporterElementParser found for reporter type '${metrics.reporter.type}'
I'm using this configuration method (via properties file) for mongo host and port and it works like a charm.
I'm running in Tomcat7, Spring 4.0.5.RELEASE, metrics framework 3.1.0-SNAPSHOT (I need jersey 2 support) and metrics-spring 3.0.1. I also tried with a self-compiled metrics-spring 3.1.0-SNAPSHOT but doesn't solve my problem.
[EDIT]
Found this issue which explain that SpEL is not supported by the ElementParser.

I'm afraid it isn't possible to use a property placeholder in the type attribute. Spring does not resolve property placeholders or SpEL until the phase after metrics-spring reads the type attribute and parses the reporter element (which is necessary to allow placeholders and bean references to be used in all the other attributes).
A possible solution would be to configure all the reporters you might want to use, and use a placeholder in the enabled attribute:
<metrics:reporter metric-registry="metrics" type="console" period="1m"
enabled="${metrics.reporter.console.enabled}" />
<metrics:reporter metric-registry="metrics" type="slf4j" period="1m"
enabled="${metrics.reporter.slf4j.enabled}" />
And the properties file:
metrics.reporter.console.enabled=true
metrics.reporter.slf4j.enabled=false
I hope this makes sense, I've had a very long week!

Related

IBM MQ and Spring Integration - security settings

I've got a Spring Integration flow which uses an inbound gateway to get messages from an IBM MQ queue:
<int-jms:inbound-gateway id="InputGateway"
request-destination="RequestQueue"
request-channel="RequestChannel"
reply-channel="ReplyChannel"
/>
However I'm not capable of assigning security settings. In particular, I need an username, password and userAuthenticationMQCSP = false (for reasons beyond the scope of this post, I won't get into details but my broker will throw a MQRC = 2009 otherwise).
I've followed the IBM guide to connect with jmsTemplate and works just fine. This uses the official Spring boot starter from IBM MQ which will kindly create a connection factory and will autoconfigure it with some defaults from application.properties:
ibm.mq.queueManager=myQMName
ibm.mq.channel=myChannel
ibm.mq.connName=myhostname(myPort)
ibm.mq.user=username
ibm.mq.password=*******
ibm.mq.userAuthenticationMQCSP=false
Now, back to the Spring Integration case. According to the int-jms:inbound-gateway spec, a connectionFactory will be injected to the gateway, by name (attribute: connection-factory) which is set up to be "jmsConnectionFactory" by default
By default, all of the JMS adapters that require a reference to the
ConnectionFactory automatically look for a bean named
jmsConnectionFactory. That is why you do not see a connection-factory
attribute in many of the examples. However, if your JMS
ConnectionFactory has a different bean name, you need to provide that
attribute.
I don't see any way to set up a predictable name for the connection factory that I can plug into the int-jms:inbound-gateway.
Now, taking a different approach, as per this example I've created my connectionFactory with an adecuate name:
<bean id="jmsConnectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory">
<property name="transportType" value="1"/>
<property name="queueManager" value="myQMName"/>
<property name="hostName" value="myhostname"/>
<property name="port" value="myPort" />
<property name="channel" value="myChannel"/>
</bean>
But now I need somewhere to put the credentials and the security parameters. Looking at the example above, it looks like I need to plug something like:
<bean id="secureJmsConnectionAdapter" class="**yourpackages.SecureJMSConnectionAdapter**">
<property name="targetConnectionFactory" ref="${jms.mq.connection.factory}" />
<property name="userName" value="${jms.username}"/>
<property name="pwdAlias" value="${jms.alias}"/>
</bean>
However it is unclear to me how to implement this SecureJMSConnectionAdapter.
Additionally, if I set up my own connection factory, I will lose all of MQ boot starter automagic thanks to this annotation on the MQAutoConfiguration class:
#ConditionalOnMissingBean(value=javax.jms.ConnectionFactory.class)
Any ideas on how to put these pieces together?
EDIT: Just to avoid any possible red herrings to anyone, the MQRC2009 was irrelevant to ibm.mq.userAuthenticationMQCSP=false.
Some of my old projects I used a bean like this:
<bean id="jmsQueueConnectionFactory"
class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
<property name="targetConnectionFactory" ref="jmsConnectionFactory"/>
<property name="username" value="${jms.username}"/>
<property name="password" value="${jms.alias}"/>
</bean>
Should work well as a wrapper for your com.ibm.mq.jms.MQQueueConnectionFactory, but you have to use this jmsQueueConnectionFactory in the target components.
Although it looks like the mentioned IBM MQ JMS Spring doesn't that for us properly exposing a jmsConnectionFactory bean. You can rely on the default from Spring Integration in this case or use that jmsConnectionFactory explicitly for the connection-factory.
Also with Spring Boot you should consider to go away from XML configuration and give a chance for Spring Integration Java DSL: https://docs.spring.io/spring-integration/docs/5.1.7.RELEASE/reference/html/#java-dsl

Configure internationalization from application.properties in spring boot

I was wondering if I can configure how spring boot handles internationalization using the application.properties file instead of writing it in code.
For example:
To define a LocaleChangeInterceptor I have to declare a bean like this:
<bean id="localeChangeInterceptor"
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="lang" />
</bean>
However, a look at the most used properties in the documentation shows only 3 values that can be configured for internationalization:
# INTERNATIONALIZATION (MessageSourceAutoConfiguration)
spring.messages.basename=messages
spring.messages.cache-seconds=-1
spring.messages.encoding=UTF-8
So is there a way to achieve this? is there a convention on how to map this to a properties file?
is there a convention on how to map this to a properties file?
No there isn't. It's only a single bean definition and it's entirely optional, so I would prefer to leave that in Java.

How to configure properties in XML?

I am planing to Maven develop a module that actually needs to read configuration data something like below, where tag <path> will be repeated multiple times with different path name and can be same <pathtype> and different URL and parameters and then attempt to access those URLs and paths in Java classes.
In Java I should be able to read all <pathurl> tags and its parameters for given type. then I will process them in Java one by one.
What is best way to configure this data and read in Java? Should it be normal properties file loading process by Java or there is any new best practice using spring or any other utility.
Basically I want to know is there any way of configuring data other than in this XML format and then parsing it? Since the data is static in that XML, my client don't want to use database.
<path>
<pathname>mypath</pathname>
<pathtype>httpfile</pathtype>
<pathurl>http://acdsds:8380/gis/</pathurl>
<params>
<user>sad</user>
<password>spwd</password>
<httprescd>100</httprescd>
<mexist>DROD_MEF.gif</mexist>
</params>
</path>
When it comes to configuring software using certain properties such as URL's, passwords and unique keys in spring PropertyPlaceHolderConfigurer is your best bet.
From spring document:
You use the PropertyPlaceholderConfigurer to externalize property values from a bean definition in a separate file using the standard Java Properties format. Doing so enables the person deploying an application to customize environment-specific properties such as database URLs and passwords, without the complexity or risk of modifying the main XML definition file or files for the container.
What you will do is, put all your configuration data in a properties file:
##JDBC related properties start here##
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.dialect=org.hibernate.dialect.MySQLDialect
jdbc.databaseURL=jdbc:mysql://localhost:3306/databaseName
jdbc.userName=root
jdbc.password=root
##JDBC related properties end here##
## path Configuration start here##
path.name=mypath
path.type=httpfile
path.url=http://acdsds:8380/gis/
## path Configuration ends here##
Then, configure spring to access external properties file(assuming your properties file is named settings.properties):
<!--settings for accessing external property files-->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>/yourPathToPropertiesFile/settings.properties</value>
</list>
</property>
</bean>
After you have configured PropertyPlaceholderConfigurer, access your properties by simple using #value annotation, wherever you want.
#Value("${path.name}")
String pathName;
You can even use properties file to configure you data source and many other stuff:
<bean id="dataSource" destroy-method="close"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.databaseURL}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
You should probably start by reading some basic tutorials on XML processing in Java. I'm biased, but my standard recommendation is still the material at IBM's DeveloperWorks XML site
You can use json configuration file and Google's Gson(https://code.google.com/p/google-gson/) to parse the json file. Refer to this thread Parse a nested JSON using gson on how to use Gson library & sample json format.

property not found with multiple context:property-placeholder

I am using spring 3.1 with spring profiles to load the beans. In my app context file, I load the properties like :
<context:property-placeholder order="1" location="classpath*:META-INF/spring/*_${spring.profiles.active}.properties" ignore-unresolvable="true"/>
And then I use the property value to load the data source bean like
<property name="driverClassName" value="${database.driverClassName}"/>
It works fine.
The problem starts when I add a couple of more property placeholders so that properties from some database tables can be loaded.
This uses a properties reference loaded by
<bean id="configFactoryBean"
class="org.springmodules.commons.configuration.CommonsConfigurationFactoryBean">
<constructor-arg ref="globalSystemConfiguration"/>
</bean>
To add to the details, this configFactoryBean uses the datasource to load the properties from the database.
When I do this, I have the following exception:
java.lang.ClassNotFoundException: ${database.driverClassName}
My analysis is that its trying to load the datasource before resolving the property from the first context property placeholder. I may be wrong. Or maybe spring profile variable is not resolved properly.
Can anyone please help me to fix this.
Thanks
Akki
This bug about multiple property placeholders might relate to your problem: https://jira.spring.io/browse/SPR-9989
When using multiple PropertyPlaceholderConfigurer in conjunction with
#Value annotation and default value for placeholders syntax (ie
${key:defaultValue}), only the first PropertyPlaceholderConfigurer is
used. If this configurer does not contain the desired value, it falls
back to #Value default even if the second
PropertyPlaceholderConfigurer contains the value.
Affects Version/s: 3.1.3
Each <context:property-placeholder> creates a new instance of PropertyPlaceholderConfigurer - it gets messy easily. You should have one such thing per application and on application level, not on libraries' one - that makes maintenance much easier.
For more details and a suggestion how to cope with it look here:
http://rostislav-matl.blogspot.cz/2013/06/resolving-properties-with-spring.html
In my application I am using property-placeholder configurer in following way and it works very well. You can try that.
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath*:META-INF/spring/*_${spring.profiles.active}.properties</value>
</list>
</property>
</bean>
I think this should resolve your problem. :)
Since you have suggested hardcoding the path to the configuration file works, try using the profiles attribute on the tag to selectively include the configuration.
<beans profile="profileName">
<context:property-placeholder order="1" location="classpath*:META-INF/spring/hardcoded.properties" ignore-unresolvable="true"/>
</beans>
<beans profile="profileName2">
<context:property-placeholder order="1" location="classpath*:META-INF/spring/hardcoded.properties" ignore-unresolvable="true"/>
</beans>
See this article explaining profiles: http://java.dzone.com/articles/using-spring-profiles-xml

How to change the TaskExecutor implementation dynamically depending on the application server

I am using Spring 3.0.x to get a WorkManager from an application server and use it to run scheduled jobs that need database access. The problem is, is that this application could be deployed to different Java application servers - in this case, to Websphere 7.0 and GlassFish 3.1 OSE. (Crazy combo, I know...)
The problem I am having is that before deploying to either, I have to change the bean to reference the appropriate TaskExecutor class used for each server. I have Spring load up an applicationContext.xml with these beans in it.
For Websphere, I have to pull the WorkManager externally and use the following bean:
<bean id="myTaskExecutor" class="org.springframework.scheduling.commonj.WorkManagerTaskExecutor">
<property name="workManagerName" value="wm/default" />
<property name="resourceRef" value="true"/>
</bean>
and the web.xml has something like this:
<resource-ref>
<description>WorkManager</description>
<res-ref-name>wm/default</res-ref-name>
<res-type>commonj.work.WorkManager</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
For GlassFish, I can just use the bean:
<bean id="myTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
</bean>
Can I somehow dynamically change which TaskExecutor implementation is used on the fly?
I could easily check for the Websphere resource to determine if I am on Websphere, then fall back to GlassFish. But how to load a class like that with Spring (using Annotations or otherwise) is baffling me.
Any help is appreciated. Thanks!
P.S. I am not worried about being J2EE compliant for GlassFish - it's just that Websphere forces you to be so (hence pulling an external WorkManager)
You can easily use a custom VM argument to determine what environment you are running in, and use that to load the appropriate context file.
One file for each supported environment, all of which define the same bean.
task-exec-was.xml
task-exec-glassfish.xml
Add a required VM argument.
-Dapp.server=was
Then, wherever you actually load the bean you include the appropriate file based on a PropertyPlaceholderConfigurer.
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" />
<import resource="task-exec-${app.server}.xml" />
Edits based on information in the comments.
You can override for the environment you do have control over in this case.
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
<property name="location" value="classpath:spring/was.properties/>
</bean>
<import resource="task-exec-${app.server}.xml" />
Now you have a file called spring/was.properties that defines a property app.server=was, which is read by default. In Glassfish, you supply the same property as a VM argument, which will now override the property read from the file.

Categories

Resources