Subsets of Properties With Spring - java

Suppose I have a properties file with contents looking like this:
local.jndi.datasource = localDataSource
dev.jndi.datasource = devDataSource
test.jndi.datasource = testDataSource
prod.jndi.datasource = prodDataSource
I have system variables called "app.configDir" and "app.environment". The app.environment variable can be "local","dev","test", or "prod".
What I would like to do is something like this:
<context:property-placeholder location="file:#{systemProperties['app.configDir'] }/>
However, I would like to have the properties narrowed down to the subset defined in the environment variable.
Is there a relatively easy way to do this in XML configuration? I can think of a couple of ways to do this if I were able to use programatic configuration.
Edit: Currently using Spring 3.1.

You should be able to use spring profiles as of Spring 3.1. so in your config you can have multiple and place the
<beans profile="local">
<context:property-placeholder order="1" location="classpath*:META-INF/spring/some.properties"/>
</beans>
<beans profile="dev">
<context:property-placeholder order="1" location="classpath*:META-INF/spring/someOther.properties"/>
</beans>
see the following link for a full example on using Spring profiles:
http://java.dzone.com/articles/using-spring-profiles-xml

In XML in Spring 3.1 you can do this:
<context-param>
<param-name>spring.profiles.default</param-name>
<param-value>${app.configDir}</param-value>
</context-param>
This will enable a profile (dev/test/prod), but first define the beans using the profile:
<beans profile="dev">
<jdbc:embedded-database id="dataSource">
<jdbc:script location="classpath:update.sql" />
</jdbc:embedded-database>
</beans>
<beans profile="qa">
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:url="jdbc:h2:tcp://dbserver/~/mydb"
p:driverClassName="org.h2.Driver"
p:username="sa"
p:password="password"
p:initialSize="20"
p:maxActive="30" />
</beans>

Related

MessageSource getMessage method not working in Spring mvc

I have developed a Spring mvc application where I want to read some property value
from properties file located inside of weblogic server.
Have performed following steps:
Created a project specific folder appConfig in following path: Oracle/Middleware/ORACLE_HOME/user_projects/domains/wl_server/config/rmsConfig
Placed the properties file named commonConfig.properties inside of it.
Have also edited setDomainEnv.cmd with following entry,
if NOT "%EXT_POST_CLASSPATH%"=="" (
set EXT_POST_CLASSPATH=%EXT_POST_CLASSPATH%;%DOMAIN_HOME%\config\appConfig
if NOT "%POST_CLASSPATH%"=="" (
set POST_CLASSPATH=%POST_CLASSPATH%;%EXT_POST_CLASSPATH%
) else (
set POST_CLASSPATH=%EXT_POST_CLASSPATH%
)
)
Please find below my Spring bean configuration file for this:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd">
<bean id="commonProps" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="commonConfig" />
<property name="cacheSeconds" value="120" />
</bean>
</beans>
In my Java Spring bean class I am refering to this as follows:
#Component
public class LocationClient{
#Autowired
private MessageSource commonProps;
public void showMessage(){
System.out.println(commonProps.getMessage("common.line", null, null, null));
}
}
Now commonProps is not null but "common.line" printing null in console.
Please find below property file entry:
common.line=382
Anyone has any suitable solution to this???
I think you have to add your property file in classpath or in WEB-INF folder.
This is the note from the Java Spring docs.
For a typical web application, message files could be placed in
WEB-INF: e.g. a "WEB-INF/messages" basename would find a
"WEB-INF/messages.properties", "WEB-INF/messages_en.properties" etc
arrangement as well as "WEB-INF/messages.xml",
"WEB-INF/messages_en.xml" etc. Note that message definitions in a
previous resource bundle will override ones in a later bundle, due to
sequential lookup.
Refer the link for more information: ReloadableResourceBundleMessageSource
One possible solution is to use ResourceBundleMessageSource instead of ReloadableResourceBundleMessageSource in order to define your properties like this:
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="commonConfig" />
</bean>
Also make sure that commonConfig.properties is inside of your WEB-INF folder, for example if your application is appConfig then it should be on the root of your classpath: appConfig/WEB-INF/classes/commonConfig.properties
Second alternative if you need commonConfig.properties outside classpath, using your first approach (make sure that the bean id is messageSource)
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="file:/your/absoulute/path/commonConfig" />
<property name="cacheSeconds" value="120" />
</bean>

How to load properties for Blueprint XML from database

I need to load some properties for Blueprint XML from database. How to do this in Blueprint XML? I have struggled to find good examples for Blueprint. Is there something similar to Spring PropertyPlaceholderConfigurer?
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxrs="http://cxf.apache.org/blueprint/jaxrs"
xmlns:cxf="http://cxf.apache.org/blueprint/core"
xsi:schemaLocation="
http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
http://cxf.apache.org/blueprint/jaxrs http://cxf.apache.org/schemas/blueprint/jaxrs.xsd
http://cxf.apache.org/blueprint/core http://cxf.apache.org/schemas/blueprint/core.xsd">
<jaxrs:server id="restService" address="{{url.in}}">
<jaxrs:serviceBeans>
<ref component-id="restSvc"/>
</jaxrs:serviceBeans>
</jaxrs:server>
</bean>
Blueprint has also property placeholder (see apache camel documentation).
It's not as powerful as spring, but it allows to store configuration in property file (in case of karaf, in /etc directory) and karaf is configured to react to configuration change and call init-method of confiugred beans.
Sample configuration:
<cm:property-placeholder persistent-id="com.example.persistence" update-strategy="reload">
<cm:default-properties>
<cm:property name="url.in" value="example.com/rest"/>
</cm:default-properties>
</cm:property-placeholder>
Blueprint is not as powerful as Spring, so if you want something not provided there, you should either switch to Spring or rethink you architecture.

Spring Conditional Bean creation based on another bean

I'm trying to find a way to only create a bean if the value of another bean/property is true, using Spring 3.2 and XML configurations.
<bean id="isEnabled" class="java.lang.Boolean">
<bean factory-bean="configurationService" factory-method="getBooleanValue">
<constructor-arg index="0">
<util:constant static-field="org.code.ConfigurationKeys.ENABLED"/>
</constructor-arg>
</bean>
</bean>
<if isEnabled=true>
..... create some beans
</if>
I've seen some slightly similar examples using Spring EL but nothing that does this exactly...
You can use profiles.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd" >
<!-- here goes common beans -->
<beans profile="Prof_1">
<import resource="./first-config.xml" />
</beans>
<beans profile="Prof_2">
<import resource="./second-config.xml" />
</beans>
</beans>
One can activate multiple profile at same time or choose not to activate any. To activate there are multiple ways but to programtaically do this we need to add a initializer in web.xml
<context-param>
<param-name>contextInitializerClasses</param-name>
<param-value>com.test.MyCustomInitializer</param-value>
</context-param>
MyCustomInitializer looks like following
public class MyCustomInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(ConfigurableApplicationContext applicationContext) {
try {
String activeProf;
// some logic to either read file/env variable/setting to determine which profile to activate
applicationContext.getEnvironment().setActiveProfiles( activeProf );
} catch (IOException e) {
e.printStackTrace();
}
}
}
Why you don't use the factory to create the objects when are required and make them lazy.
<bean id="second "class="xxx.xxx.Class" lazy-init="true" scope="prototype"/>
There is no way to introduce if statement within the spring configuration, profiles could work but at more related to environment not a programmatic configuration.

Spring referring bean present in other xml using local attribute of ref tag

I am creating sample spring program to understand, local attribute of ref tag.
I have created two bean files
first one [applicationcontext.xml]
<bean class="org.vik.spring.SequenceGenerator" name="sequenceProperty_Other">
<property name="prefix">
<ref local="prefixGeneratorOther" />
</property>
<property name="suffix" value="23"></property>
</bean>
Second xml file [prefix_context.xml]
<bean class="org.vik.spring.DatePrefixGenerator" id="prefixGeneratorOther" p:prefix="other"/>
I have created app context like below
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("applicationcontext.xml" ,"prefix_context.xml");
When I request for bean "sequenceProperty_Other", spring successfully returns it
SequenceGenerator sequenceConstrutornerator = applicationContext.getBean( "sequenceProperty_Other",SequenceGenerator.class);
What I could understand from this, is that as "prefixGeneratorOther" bean in not in same xml file (applicationcontext.xml) and I am using local attribute to refer it, Spring should through exception. But in my case its working. Am I missing some thing.
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- <bean class="org.vik.spring.SequenceGenerator" name="sequence"> </bean> -->
<bean class="org.vik.spring.DatePrefixGenerator" id="prefixGenerator"
p:prefix="122333">
</bean>
<bean class="org.vik.spring.SequenceGenerator" name="sequenceProperty_Locale">
<property name="prefix">
<ref local="prefixGenerator" />
</property>
<property name="suffix" value="23"></property>
</bean>
<bean class="org.vik.spring.SequenceGenerator" name="sequenceProperty_Other">
<property name="prefix">
<ref local="prefixGeneratorOther" />
</property>
<property name="suffix" value="23"></property>
</bean>
prefix_context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="org.vik.spring.DatePrefixGenerator" id="prefixGeneratorOther" p:prefix="other"/>
</beans>
Java class
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("applicationcontext.xml",
"prefix_context.xml");
System.out.println(applicationContext.getBean("prefixGenerator", PrefixGenerator.class).getPrefix());
SequenceGenerator sequenceProperty = applicationContext.getBean("sequenceProperty_Locale",
SequenceGenerator.class);
System.out.println(sequenceProperty);
SequenceGenerator sequenceConstrutornerator = applicationContext.getBean("sequenceProperty_Other",
SequenceGenerator.class);
System.out.println(sequenceConstrutornerator);
This particular behavior works with any version after Spring 3.1.0 (included) in the 3.x branch. If you test this with the latest 3.0.x (which is 3.0.7) you'll get an exception. If you test with Spring 4, you'll get an exception, but a different one.
If you take a look carefully at the exception in Spring 3.0.7, this refers to XML parsing:
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:243)
at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:347)
at org.springframework.beans.factory.xml.DefaultDocumentLoader.loadDocument(DefaultDocumentLoader.java:75)
which means the restriction is at xml schema level (and I believe it's at Java code level, as well).
This behavior has changed in Spring 3.1.0 (and after) because of this JIRA issue. From all those JIRA issue it is linked to, this one seems to explain what happened: the restriction has been eliminated from 3.1 schema and the ref local entered in a kind of "deprecated" state (because in 3.1.x and 3.2.x one can use it) and in Spring 4 ref local has been entirely eliminated. In Spring 4 the documentation says ref local is not supported anymore and, also, the xsd schema has been updated (in the sense that ref doesn't accept local anymore).

Property 'dataSource' is required Error in java (Spring)

I am developing an web application in Java (Spring)
My java file is as,
try
{
JdbcTemplate jt = new JdbcTemplate(dataSource);
System.out.println("Connection ....."+jt.toString());
Connection conn;
Statement st;
conn =DriverManager.getConnection(jt.toString());
conn = (Connection) jt.getDataSource();
st=conn.createStatement();
System.out.println("Connection created....."+st);
}
catch (Exception e) {
System.out.println("Error Found...."+ e.getMessage());
System.out.println("Strack Trace....."+e.getStackTrace());
}
My spring-servlet.xml file is as,
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/cjbranchdb" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<bean id="JdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource"><ref bean="dataSource"/></property>
</bean>
But it gets an error as,
Error Found: Property 'dataSource' is required.
Strack Trace: [Ljava.lang.StackTraceElement;#7948dd
Here, I want to make a connection in Java file and pass it to the another variable as Jasper Report.
Please help, How to fix this issue?
I am guessing you are completely new to Java, JEE, Spring and JDBC. As I have stated in my comment, it is hard to answer your question, if what you are doing in there is incorrect in its base. I will try to go through few topics and hopefully also pin point where your current issue is.
Spring app structure
You need to be sure to correctly structure your project:
src
main
java - directory for Java sources
in/mmali/springtest/controller/IndexController.java - Your controller class
resources - directory for non-Java (re)sources
webapp - root for the web application resources
WEB-INF/web.xml - JEE web application configuration
WEB-INF/spring-servlet.xml - application context configuration for dispatcher servlet
pom.xml - Maven config (in case you are using Maven)
I would call this a common structure for Java project, mostly "standardized" by Maven.
Correct JEE config
You need to have correct web.xml configuration:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
This is a basic configuration (without root context), which will use your spring-servlet.xml as Spring context configuration.
Correct Spring configuration
You need to have correct Spring context configuration:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven />
<mvc:resources location="/resources/" mapping="/resources/**" />
<!-- With ROOT context we would restrict component scan on controllers here -->
<context:component-scan base-package="in.mmali.springtest" />
<!-- Data source configuration would normally go inside ROOT context. -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/cjbranchdb" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
This will load all classes annotated with #Component (and its companions #Controller, #Service, #Repository) as your beans. Bean in a context of Spring application is a object managed by Spring -> i.e. object which is being instantiated by Spring itself. When you want to work with a Spring bean, you need to have it injected (e.g. by using #Autowired annotation) or you need to pull it out from ApplicationContext#getBean manually.
Working with JDBC
Working with JDBC is painful with all the closeable resources and checked exceptions. That is why Spring-JDBC project wraps JDBC API so you don't have to use it.
To showcase how you should work with JDBC and also how to let Spring inject dependencies, here is a simple controller:
#Controller // Will be detected by <context:component-scan>
#RequestMapping // Will be detected by <mvc:annotation-driven> (more specifically by one of its component - RequestMappingHandlerMapping)
public class IndexController {
#Autowired // Spring will inject JdbcTemplate here
private JdbcOperations jdbcOperations;
#RequestMapping // This method should be called for requests to "/"
#ResponseBody // Returned string will be returned to client... normally you would register view resolver and just return name of a JSP to render
public String renderIndex() {
// You don't need to worry about JDBC's DataSource, Connection, ResultSet, ... just use JdbcTemplate
long rowCount = jdbcOperations.queryForLong("SELECT COUNT(*) FROM my_test_table;");
return "Number of rows in database is: " + String.valueOf(rowCount);
}
}
Note, that in a real application you would not allow controller to work with your data source directly, but rather through service and data layer.
Next steps
Start using logging system and never use System.out.println in a web application again ;). I suggest slf4j with its simple binding for start (later you can configure it to use logback or log4j).
Configure your application to use transactions. Use Spring's transaction handling (<tx:annotation-driven/> with #Transactional). It might look as magic at first, but when you discover something about AOP and proxy classes, you will then start really appretiating the principles of how Spring works.
Split your application logic to service layer and data (DAO) layer.
Check Spring's sample application (http://docs.spring.io/docs/petclinic.html) and reference application (https://github.com/spring-projects/greenhouse).
JdbcTemplate jt = new JdbcTemplate(dataSource); You cant just use new keyword to construct a bean object. Obviously the references in that object will be null.
Instead you should ask spring to give you that bean object. Some thing like this.
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-servlet.xml");
JdbcTemplate jt = (JdbcTemplate)context.getBean("JdbcTemplate");
In this case spring will inject the dependency ie datasource as given in configuration.
According to the file name, I assume you that you are building a web-based application.
For capturing the error, please use a proper logging framework instead of System.out.println.
According to the error, dataSource seems null. Please kindly check if your web.xml has defined the servlet xml file, such as
<servlet>
<servlet-name>spring_app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
In addition, DriverManagerDataSource is good enough for testing only. For production use, please consider Apache's Jakarta Commons DBCP or C3P0. See detail at the official webpage.
Since your XML file has mentioned
<bean id="JdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource"><ref bean="dataSource"/></property>
</bean>
, the XML file should consist of a servlet section to call the object of id=JdbcTemplate. For example,
<bean id="MyServlet" class="com.my.MyServlet">
<property name="jdbcTemplate"><ref bean="JdbcTemplate"/></property>
</bean>

Categories