Activating Spring Profile active JVM arguments in GWT hosted mode - spring

I have a spring profile configuration as shown below
<beans profile="dev">
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${db.driverClassName}" />
<property name="jdbcUrl" value="dfgdfg" />
<property name="user" value="${db.username}" />
<property name="password" value="${db.password}" />
</bean>
</beans>
<beans profile="prod">
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/Test"/>
</beans>
I am trying to make one of this active via the VM argument -Dspring.profiles.active="dev" . This works in Tomcat and so does the context-param route in Hosted mode via the gwt-maven-plugin but I can't get the VM arguments to work . I tried mvn -Dspring.profiles.active="dev" gwt:run also tried to pass -Dspring.profiles.active="dev" via the VM arguments under the JRE tab in run configurations along with the goal gwt:run . I also tried the environment tab and even -Dspring.profiles.active=dev but the NoSuchBeanDefinitionException doesn't budge . Is this because of the limited capability of the embedded server ?

No, simply gwt:maven plugin is kind of strange and it doesn't pass system properties to the launched JVM instance, and the only way to pass parameters is to put it into <extraJvmArgs> in plugin configuration e.g. in your case you have to add following to the configuration tag of gwt plugin:
<extraJvmArgs>-Dspring.profiles.active=dev</extraJvmArgs>
God knows why this works only this way, I wish there were some other normal way.

Related

Apache Camel Spring DSL, referring to an environment variable HOSTNAME

I am using Apache Camel 2.16.0 with Spring DSL
I have a Spring context XML in which I have defined a Property PlaceHolder to read the properties from various files as follows-
<bean id="propertyPlaceholder" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
<property name="ignoreResourceNotFound" value="false"/>
<property name="locations">
<list>
<value>classpath:/properties/versioning.properties</value>
<value>classpath:/properties/#{inetAddress.hostName}.properties</value>
</list>
</property>
</bean>
<bean id="inetAddress" class="java.net.InetAddress" factory-method="getLocalHost"/>
The property values are used to construct other beans such as -
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.gjt.mm.mysql.Driver"/>
<property name="url" value="${${LIVE_}DATASOURCE_URL}"/>
<property name="username" value="${${LIVE_}DATASOURCE_USERNAME}"/>
<property name="password" value="${${LIVE_}DATASOURCE_PASSWORD}"/>
</bean>
This works fine, I can see the beans being created.
I also have another Spring Context XML in the same app which has a camel context and I want to use the some other properties defined in the same properties files. I know that camel supports Spring Property Placeholder, see below excerpts from the context -
<camelContext id="charge-process-context" xmlns="http://camel.apache.org/schema/spring">
<propertyPlaceholder id="properties"
location="classpath:/properties/versioning.properties,
properties/${env:HOSTNAME}.properties"
xmlns="http://camel.apache.org/schema/spring" />
.....
.....
</camelContext>
As part of this context, I have a route that uses https component that uses the values from the property file such as below -
<to uri="https4:{{LIVE_AUTH_RESPONSE_HOST}}:{{LIVE_AUTH_RESPONSE_PORT}}/{{LIVE_AUTH_RESPONSE_CONTEXT_PATH}}"/>
This route does not start and throws following exception -
Caused by: java.lang.IllegalArgumentException: Cannot find system environment with key: HOSTNAME
at org.apache.camel.util.FilePathResolver.resolvePath(FilePathResolver.java:54)
at org.apache.camel.component.properties.PropertiesComponent.parseLocations(PropertiesComponent.java:434)
at org.apache.camel.component.properties.PropertiesComponent.parseUri(PropertiesComponent.java:163)
at org.apache.camel.component.properties.PropertiesComponent.parseUri(PropertiesComponent.java:148)
at org.apache.camel.impl.DefaultCamelContext.resolvePropertyPlaceholders(DefaultCamelContext.java:2261)
at org.apache.camel.model.ProcessorDefinitionHelper.resolvePropertyPlaceholders(ProcessorDefinitionHelper.java:730)
at org.apache.camel.model.ProcessorDefinition.createOutputsProcessorImpl(ProcessorDefinition.java:427)
at org.apache.camel.model.ProcessorDefinition.createOutputsProcessor(ProcessorDefinition.java:413)
at org.apache.camel.model.ProcessorDefinition.createOutputsProcessor(ProcessorDefinition.java:165)
at org.apache.camel.model.ExpressionNode.createFilterProcessor(ExpressionNode.java:109)
at org.apache.camel.model.WhenDefinition.createProcessor(WhenDefinition.java:74)
at org.apache.camel.model.WhenDefinition.createProcessor(WhenDefinition.java:32)
at org.apache.camel.model.ProcessorDefinition.createProcessor(ProcessorDefinition.java:483)
at org.apache.camel.model.ChoiceDefinition.createProcessor(ChoiceDefinition.java:135)
at org.apache.camel.model.ProcessorDefinition.makeProcessorImpl(ProcessorDefinition.java:534)
at org.apache.camel.model.ProcessorDefinition.makeProcessor(ProcessorDefinition.java:495)
at org.apache.camel.model.ProcessorDefinition.addRoutes(ProcessorDefinition.java:219)
at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:1069)
Please Note: I am deploying my application as a war file on Tomcat 8 on an AWS instance.
I have a Dev Environment on Windows 10 and I have found this working on the Windows OS. I have also seen that the file FilePathResolver.java in Apache Camel 2.16 uses System.getenv(key) to obtain the value i.e. System.getenv("HOSTNAME") which returns a null on AWS instance and a correct value on Windows 10. I also tried using env:hostname (small case letters for unix) but still no luck ...
I found a solution at http://camel.apache.org/using-propertyplaceholder.html
at Bridging Spring and Camel Property Placeholders
It mentions following -
The Spring Framework does not allow 3rd party frameworks such as Apache Camel to seamless hook into the Spring property placeholder mechanism. However you can easily bridge Spring and Camel by declaring a Spring bean with the type org.apache.camel.spring.spi.BridgePropertyPlaceholderConfigurer, which is a Spring org.springframework.beans.factory.config.PropertyPlaceholderConfigurer type.

Jasypt and Weblogic environment variables

I am using jasypt 1.9.2 to encrypt a password in a property file for my spring REST service. I've added an environment variable to Weblogic via the Server startup arguments text box called APP_ENCRYTPION_PASSWORD, but that environment variable is not getting read by the jasypt. Here is the error:
ERROR o.s.web.servlet.DispatcherServlet - Context initialization failed
java.lang.NullPointerException: null
at org .jasypt.encryption.pbe.config.SimplePBEConfig.getPasswordCharArray(SimplePBEConfig.java:434) ~[jasypt-1.9.2.jar:na]
Here is the Weblogic environment variable logged during when the server starts up:
JAVA_OPTIONS= -Dother.vars=xxx -DAPP_ENCRYPTION_PASSWORD=password -Dmore.vars=yyy
I've traced the jasypt code and it seems jasypt does not parse the environment variables within JAVA_OPTIONS. I know this works for other frameworks like spring since we have other environment variables within JAVA_OPTIONS that spring has no issue reading.
I could add the environment variable to the startup scripts (setEnv.sh I think) for weblogic, but that will add the variable for all managed nodes instead of the one cluster my app is deployed to.
Is there a different way to configure jasypt within spring to get the environment variables within JAVA_OPTIONS?
Here is my spring config:
<bean
class="org.jasypt.spring31.properties.EncryptablePropertyPlaceholderConfigurer">
<constructor-arg>
<bean class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor">
<property name="config">
<bean class="org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig">
<property name="algorithm" value="PBEWithMD5AndTripleDES" />
<property name="passwordEnvName" value="APP_ENCRYPTION_PASSWORD" />
</bean>
</property>
</bean>
</constructor-arg>
<property name="location">
<value>application.properties
</value>
</property>
</bean>
My application.properties file contents:
username=someuser
password=ENC(encryptedstring)
UPDATE for clarity:
Adding the environment variable to weblogic via setEnv.sh or Eclipse works just fine. It's only when I use the weblogic console to add the environment variable for a cluster that jasypt fails to parse the value since it is within JAVA_OPTIONS.
You can use passwordSysPropertyName instead of passwordEnvName. This way you can use -DpasswordSysPropertyName="mysecret"
<bean id="environmentVariablesConfiguration"
class="org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig">
<property name="algorithm" value="PBEWithMD5AndDES" />
<property name="passwordSysPropertyName" value="APP_ENCRYPTION_PASSWORD" />
</bean>

Could not resolve placeholder in string value with external files

I have configured a config.xml file choosing the appropriate properties file depending on environment. I am running this as a Spring Boot app with Apache Camel.
The config looks like this.
<bean id="properties"
class="org.apache.camel.component.properties.PropertiesComponent">
<property name="locations" ref="locations" />
</bean>
<bean id="bridgePropertyPlaceholder"
class="org.apache.camel.spring.spi.BridgePropertyPlaceholderConfigurer">
<property name="locations" ref="locations" />
<property name="ignoreUnresolvablePlaceholders" value="true" />
</bean>
<beans profile="dev">
<util:list id="locations">
<value>classpath:config/users.properties</value>
<value>classpath:config/application.properties</value>
<value>classpath:config/application-dev.properties</value>
</util:list>
<beans profile="test">
<util:list id="locations">
<value>file:${project.dir}/config/users.properties</value>
<value>file:${project.dir}/config/application.properties</value>
</util:list>
When using the test profile I want to use the external files defined in the config (because I dont want to commit username/password to repo). That seems to work okay.
However, my users.properties file contains:
username=myusername
password=mypassword
and my application.properties contains:
loginParameters=username=${username}&password=${password}
when running java -jar myjar.jar --spring.profiles.active=test I encounter:
java.lang.IllegalArgumentException: Could not resolve placeholder 'username' in string value '${username}&password=${password}'
It clearly loads the properties files because it states:
Loading properties file from URL: file:...../users.properties
Loading properties file from URL: file:...../application.properties
Bridging Camel and Spring property placeholder configurer with id: bridgePropertyPlaceholder
...
And then the exception occurs. How can I resolve the issue where the application.properties file doesn't recognize my properties defined in users.properties? Everything works okay when running the dev-profile.
in your application properties, use $simple{username} and $simple{password} to tell Camel to put the values there.

Spring JNDI datasource not recognized after upgrade to ActiveMQ 5.6.0

I tested a ActiveMQ 5.5.0 (fuse version) app in AMQ 5.6.0 and noticed that our Spring JNDI configured Oracle datasources aren't being found.
The only thing I changed in my applications was the pom.xml versions of AMQ/Spring (to match the 5.6 versions). Otherwise, I'm using the identical application code and configuration (activemq.xml, jndi.xml, etc), but my Spring JDBC DAOs (v3.0.5) are failing to find them.
No errors in the logs otherwise, just this Spring Application Context initialization error...
javax.naming.NameNotFoundException; remaining name 'jdbc/myDataSource'
here is the relevant Spring jndi config (conf/jndi.xml, included in conf/activemq.xml)...
<bean id="jndi" class="org.apache.xbean.spring.jndi.SpringInitialContextFactory"
factory-method="makeInitialContext" scope="singleton">
<property name="entries" ref="jndiEntries" />
</bean>
<util:map id="jndiEntries">
<entry key="jdbc/myDataSource">
<bean id="myDBCPDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.OracleDriver" />
...
then my application references it like this...
<bean id="myDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>jdbc/myDataSource</value>
</property>
</bean>
<bean id="messageDAO" class="com.mycompany.MessageDAOImpl">
<property name="dataSource" ref="myDataSource" />
</bean>
That said, I tested without using JNDI (instead just hardcoded the datasource in my app) and everything works as expected. So that should rule out everything except the Spring JNDI registration/lookup of the datasource, etc.
So, what am I missing?
ActiveMQ has a dependency into xbean-spring, which you are using as a JNDI provider. It is likely that the transitive Xbean dependency has changed because of the upgrade to ActiveMQ 5.6.0.
I found the issue, I added a jndi.properties file under the /conf directory containing the following and it works fine now (didn't need this under AMQ 5.5...strange)...
java.naming.factory.initial = org.apache.xbean.spring.jndi.SpringInitialContextFactory

Weblogic classpath and Spring Resources

I'm trying to set a bean property like this:
<bean id="threadImport" class="com.foo.bat.util.ThreadImport" singleton="false">
<property name="mailSender" ref="mailSender"/>
<property name="parseConfFile" value="classpath:parse/import.xml" />
<property name="logFilename" value="/tmp/import.log" />
but none of files are found. What's the classpath for my deployed application? May I set it on any weblogic xml descriptors? Which is the best way to place and locate files used on spring applications?
I am using:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:foobar-config.properties" />
</bean>
The properties file is either location at the root of my test source folder so JUnit has a test-specific config available and in production, we have added a classpath entry to Weblogic pointing to the configuration folder. You can do that in the setDomainEnv.sh or for Managed Servers, in their configuration (web console), server start, classpath.

Resources