Cloud properties not read by Spring application in Cloudfoundry - java

I am deploying a Spring application in Cloudfoundry which needs to access mysql database. Now as per the tutorial , if the spring version is higher than 3.1, i can use profiles for the cloud and the cloud properties will be available for the application. The mysql service is registered as p-mysql in my case so my spring config looks like this
<beans profile="cloud">
<context:property-placeholder location="classpath:/app.conf" />
<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"
p:location="file:#{systemProperties['app.conf']}" />
<bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<!-- DB connection properties -->
<property name="driverClass" value="${db_driver:oracle.jdbc.OracleDriver}" />
<property name="jdbcUrl" value="${cloud.services.p-mysql.connection.jdbcUrl}" />
<property name="user" value="${cloud.services.p-mysql.connection.username}" />
<property name="password" value="${cloud.services.p-mysql.connection.password}" />
</bean>
</beans>
I need the app.conf for other keys not related to db services. When i deploy this i get the error
OUT org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean definition with name 'datasource' defined in URL [jar:file:/home/vcap/app/.java-buildpack/tomcat/webapps/ROOT/WEB-INF/lib/test-server-1.3.0.BUILD-SNAPSHOT.jar!/spring-bootstrap.xml]: Could not resolve placeholder 'cloud.services.p-mysql.connection.jdbcUrl'
Is there something i missed , when i look for the env for app, i do see the properties are available for the app (cf env app_name)
What i could have missed? do i have to include
cloudfoundry-runtime in the pom which i dont have now?
or include the cloud namespace in the spring app

Any documentation that mentions cloudfoundry-runtime is obsolete. The current documentation recommends the use of Spring Cloud Connectors for Spring applications on Cloud Foundry.
You should include Spring Cloud Connectors in your project, then you could do something as simple as this:
<cloud:data-source id="datasource" service-name="mysql-service"/>
You could also create the datasource bean yourself using property placeholders if you really need more control. Additional documentation on configuring Spring Cloud Connectors via XML is here: https://github.com/spring-cloud/spring-cloud-connectors/tree/master/spring-cloud-spring-service-connector#the-cloud-namespace

Related

How to register Spring Cloud config server before any XML bean is declared?

I am trying to migrate a spring app who uses PropertyPlaceholderConfigurer to resolve all the XML placeholders in it's bean declarations to a spring cloud usage, I can check that the config server is contacted and responds with the respective data generated from a git repository, however, at server startup during the BeanFactoryPostProcessor registration the XML context fails to resolve the placeholders.
I assumed that by removing the bean definition:
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="ignoreUnresolvablePlaceholders" value="false" />
<property name="properties">
<bean class="org.apache.commons.configuration.ConfigurationConverter"
factory-method="getProperties">
<constructor-arg>
<ref bean="domainConfiguration" />
</constructor-arg>
</bean>
</property>
</bean>
And adding the POM dependency for config client and respective enviroment variables the placeholders should work but they dont.
Can I manually set the config server in a higher priority?
Or as an alternative, teach PropertyPlaceholderConfigurer to consume a config server?
If you are using spring-cloud-config, this should work out of the box. When spring will build/start the ApplicationContext, first it will create a bootstrap (parent) context which will happen before creating the main context. Getting the properties of the config server should happen in the bootstrap phase so that your beans which are created in the normal context should be able to get those properties.
Check out the Client Side Usage part of the documentation for an example and check out the usage of the bootstrap.properties file.
If you don't have spring-boot (it should work w/o it as well but the docs are spring-boot centric), check out this repo or this GitHub issue, you will need a ConfigServicePropertySourceLocator.

jndi look up for DefaultFtpSessionFactory

I have ftp connection properties in .properties file and following code for spring bean.
<bean id="ftpConnectionFactory" class="org.springframework.integration.ftp.session.DefaultFtpSessionFactory">
<property name="host" value="${ftp.host}"/>
<property name="port" value="${ftp.port}"/>
<property name="username" value="${ftp.username}"/>
<property name="password" value="${ftp.password}"/>
</bean>
Above method does work using properties file inside web app and placeholder configuration. But what I want is to keep these properties in server, let's say tomcat context.xml file.
I have spring integration which uses this factory.
<int-ftp:outbound-channel-adapter id="ftpOutbound"
channel="ftpChannel"
remote-directory="${ftp.remoteDir}"
remote-file-separator="\"
session-factory="ftpConnectionFactory"
/>
Is there a way that I can externalize these properties in server and look up using jndi. For datasource I am currently doing it. But I don't know how to do it for session factory. The reason why I want to do this is to hide the password and other details.
If Tomcat can correctly bind the object to the JNDI from context.xml, there is no difference to get access to that object from JNDI lookup as you do it for DataSource.
Show, please, how you do it for DataSource from Spring, and how you configure ftpConnectionFactory, and I'll try to help you.
You could use a PropertyPlaceholderConfigurer as follows
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:external.properties</value>
</property>
</bean>
See more examples at 5.8.2 Customizing configuration metadata with a BeanFactoryPostProcessor and Spring PropertyPlaceholderConfigurer Example

Overriding properties with System in Spring

I develop a rest WS that will run on AWS BeanStalk.
For the moment, the datasource is configured with property files:
database.driverClass=org.postgresql.Driver
database.jdbcUrl=jdbc:postgresql://localhost:5432/public
database.username=postgres
database.password=postgres
And in context.xml:
<bean id="dataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
<property name="driverClass" value="${database.driverClass}" />
<property name="jdbcUrl" value="${database.jdbcUrl}"/>
....
But now, I need to have a preprod environnement, using AWS Beanstalk, that expose my system properties like RDS_HOSTNAME, RDS_PORT, RDS_DB_NAME, ...
Is there a way to keep the same system, like writing
database.jdbcUrl=jdbc:postgresql://#{RDS_HOSTNAME}:#{RDS_PORT}/#{RDS_DB_NAME}
In preprod.property?
Or to reset database.jdbcUrl with system property in context.xml?
You could do
<context:property-placeholder ignore-unresolvable="true" ignore-resource-not-found="true" location="classpath:database.properties, file:preProd.properties" />
And preProd.properties will be on the preprod machine. The keys will be the same but the values will be different. This way if preProd.properties is not found (on dev machine for example) the database.properties will be used. If the file preProd.properties is present it will override the values from database.properties.
If you are using maven you could also use maven profile and maven-replacer-plugin.

How to stick with both XML and Annotation based configuration Spring

Currently i am using spring 2.5 XML based configuration for bean. Now i want to upgrade it to Spring 3.x. I want to know after upgrading to 3.x my old XML configuration will work or not. If works then can i write annotation based configuration for new work in my current project.
Example of XML configuration:
<bean id="addTestimonialController" class="com.eam.web.testimonial.AddTestimonialController" singleton="true">
<property name="branchManager" ref="branchMan"/>
<property name="userManager" ref="userMan"/>
<property name="itemManager" ref="itemMan"/>
<property name="vendorManager" ref="vendorMan"/>
<property name="categoryManager" ref="categoryMan"/>
<property name="lineupManager" ref="lineupMan"/>
<property name="testimonialManager" ref="testimonialMan"/>
<property name="categoryMenuManager" ref="categoryMenuMan"/>
<property name="setManager" ref="setMan"/>
<property name="configurationManager" ref="configMan"/>
<property name="cartManager" ref="cartMan"/>
<property name="employeeManager" ref="employeeMan"/>
<property name="employeeBranchManager" ref="employeeBranchMan"/>
<property name="orderItemManager" ref="orderItemMan"/>
<property name="orderFaxManager" ref="orderFaxMan"/>
<property name="sessionForm" value="true"/>
<property name="commandName" value="addTestimonialBean"/>
<property name="branchesVendorManager" ref="branchesVendorMan" />
<property name="commandClass" value="com.eam.bus.testimonial.TestimonialBean"/>
<property name="validator" ref="addTestimonialValidator"/>
<property name="formView" value="addtestimonial"/>
<property name="successView" value="listtestimonials.html"/>
</bean>
Please help me. Also let me know if you similar link where somebody has explained both the configuration in a single configuration file.
Appreciate your help.
You can very well use both XML based metadata and Annotation based configuration metadata in your application. The configuration metadata is the information how you tell the Spring container to instantiate, configure, and assemble the objects in your application. Configuration metadata is traditionally supplied in a simple and intuitive XML format. i.e XML based configuration metadata. Spring 2.5 introduced support for annotation-based configuration metadata.Starting with Spring 3.0, many features provided by the Spring JavaConfig project became part of the core Spring Framework. Thus, you have different ways of providing your configuration metadata of your application through XML, Annotation based and Java config from Spring 3.x versions. This link will take you in the right direction. You must have to learn IOC chapter in Spring documentation
you can use both annotation based configuration and xml based (ControllerClassNameHandlerMapping ) by specifying the order of these handlers.
for annotation based Configuration use below
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" >
<property name="order" value="0"/>
</bean>
for annotation based configuration we have to provide location ie: where to locate annotated controllers.
<context:component-scan base-package="ur packageName" />
here package name will be the package where #Controller classes are located.
for Controller Class Name based url Mapping
<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" >
<property name= "order" value="2"/>
</bean>

Controlling log file location via JNDI in Spring?

I have a Java web application that uses the SLF4J logging facade. To date, we use the Log4J implementation underneath (though we are considering a switch to Logback). Log4J is currently configured via a log4j.xml configuration file that is placed in the root of our classpath.
In any event, we use JNDI to configure other aspects of our application so I am very familiar with how to set that up and pull a string from JNDI into a Spring configuration file.
However, I am at a loss to figure out how to create a Log4J appender from within a Spring configuration file. Better yet, can one completely configure Log4J via Spring and skip the log4j.xml configuration file altogether? I am hoping I don't have to do this programmatically.
I found a Spring class called Log4jWebConfigurer but this requires that the WAR run exploded (don't want that if I can help it) and also that the log file resides within the web-app directory (definitely don't want that).
First get the main directory via JNDI:
<jee:jndi-lookup id="myAppHome" jndi-name="myAppHome" />
Then use that bean in a Spring Expression Language statement in the the following way:
<bean id="log4jInitialization" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="org.springframework.util.Log4jConfigurer" />
<property name="targetMethod" value="initLogging" />
<property name="arguments">
<list>
<value>#{ myAppHome + '/conf/log4j.xml'}</value>
</list>
</property>
</bean>

Categories