How to load properties for Blueprint XML from database - java

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.

Related

Cloud properties not read by Spring application in Cloudfoundry

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

Subsets of Properties With Spring

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>

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>

Can I have multiple bean interconnection versions with Spring?

Spring configuration file creates beans and interconnects them. Is this correct? I have a chain of beans in my application but want to test it with smaller chains. Can I have multiple chains defined with Spring? Or only one bean structure is allowed?
EXAMPLE
Suppose this is production config:
<bean id="provider"
class="tests.Provider">
</bean>
<bean id="processor1" class="tests.Processor1">
<property name="input" ref="provider"/>
</bean>
<bean id="processor2" class="tests.Processor2">
<property name="input" ref="processor1"/>
</bean>
<bean id="consumer" class="tests.Consumer">
<property name="input" ref="processor2"/>
</bean>
And I want to test in the following configs:
<bean id="provider"
class="tests.Provider">
</bean>
<bean id="analyzer" class="tests.Analyzer">
<property name="input" ref="provider"/>
</bean>
And:
<bean id="provider"
class="tests.Provider">
</bean>
<bean id="processor1" class="tests.Processor1">
<property name="input" ref="provider"/>
</bean>
<bean id="analyzer" class="tests.Analyzer">
<property name="input" ref="processor1"/>
</bean>
And so on, attaching beans one by one.
Yes, you can.
You can break overall configuration of Spring application context for your application into parts (XML files if you use XML configuration, packages with #Components if you use classpath scanning, #Configurations if you use Java-based configuration) and construct an application context using a subset of these parts.
So, if your application has two features foo and bar, you can declare beans used by these features in foo.xml and bar.xml respectively (if you use XML configuration), and import them from the main configuration of your application (such as applicationContext.xml).
Now, if you want to write integration test for bar you can create application context from bar.xml only (#ContextConfiguration("bar.xml")). Obviously, you should take care of interdependencies between different parts of your configuration. For example, if both foo.xml and bar.xml depend on beans declared in db.xml, you may want to create something like test-db.xml and configure your integration test for bar as #ContextConfiguration({"bar.xml", "test-db.xml"}).
Note that this approach requres some discipline, especially if you use classpath scanning - in this case parts of your configuration are defined by packages, therefore you need to follow "package by feature, not by layer" rule.
See also:
9.3 Integration testing
I believe you want to test for integration, what I usually do is to separate my bean configuration files in tiers and then import them as needed for testing. Something like this:
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<context:property-placeholder
location="classpath:mx/gob/jgtjo/apps/schedule/web/schedule-web.properties"
file-encoding="UTF-8" system-properties-mode="NEVER" />
<!-- Context files -->
<import resource="spring/dataContext.xml" />
<import resource="spring/serviceContext.xml" />
<import resource="spring/securityContext.xml" />
<import resource="spring/components.xml" />
</beans>
And then, if I need to test for Daos, I only import the dataContext.xml inside a testContextDao.
In simple terms spring framework takes care of Object Creation. These objects you want Spring to manage you define them as beans. So when spring creates a bean1 if that bean1 has reference to bean2, the bean2 is instantiated and injected to bean1 and finally bean1 is created. Thinking of it as chain will be over complicating.
Section 3.2 of spring docs

Declaring an explict object dependency in Spring

The basic problem I have here is that I have one xml file that is being used as a utility file and imported into other xml files. It defines a series of objects for connecting to a platform and providing an interface to it. The beans in this file are defined to be lazy-initialised so that if you do not want to connect to the platform you will not but if you start referencing the appropriate bean then everything should get up and running.
The basic problem I have is that one of the beans in this set is not explicity referenced by any of the others but it is required to be constructed as it will call a method on one of the other beans in order to "activate" it. (It is acting as a gate keeper by switching on/off the connectivity based on what it detects as the state of the platform).
Here's a dummy of the sort of XML setup I have:
<?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"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd"
default-lazy-init="true">
<!-- Provides the connection to the platform -->
<bean id="PlatformConnection">
<constructor-arg ref="PlatformConnectionProperties" />
</bean>
<!-- This bean would be overriden in file importing this XML -->
<bean id="PlatformConnectionProperties"/>
<!-- Controls the databus to be on/off by listening to status on the Platform
(disconnections/reconnections etc...) -->
<bean lazy-init="false" class="PlatformStatusNotifier">
<constructor-arg ref="PlatformConnection" />
<constructor-arg ref="PlatformConnectionDataBus" />
</bean>
<!-- A non platform specific databus for client code to drop objects into -
this is the thing that client XML would reference in order to send objects out -->
<bean id="PlatformConnectionDataBus" class="DataBus"/>
<!-- Connects the DataBus to the Platform using the specific adaptor to manage the java object conversion -->
<bean lazy-init="false" class="DataBusConnector">
<constructor-arg>
<bean class="PlatformSpecificDataBusObjectSender">
<constructor-arg ref="PlatformConnection" />
</bean>
</constructor-arg>
<constructor-arg ref="PlatformConnectionDataBus" />
</bean>
</beans>
Now basically I want to remove the lazy-inits here that are required to get this thing to work properly. The objects referenced by the client XML are the PlatformConnection and the PlatformConnectionDataBus. How can I explicity declare that I want those other beans constructed if they are referenced?
You can add an explicit dependency from one bean to another by using the depends-on attribute:
<bean id="a" class="A"/>
<bean id="b" class="B" depends-on="a"/>
If I'm understanding your questin correctly, then I suggest you make all of your bean definitions lazy-init="true", and use depends-on to tie them together, for example:
<bean id="PlatformStatusNotifier" lazy-init="false" class="PlatformStatusNotifier">
<constructor-arg ref="PlatformConnection" />
<constructor-arg ref="PlatformConnectionDataBus" />
</bean>
<bean id="PlatformConnectionDataBus" lazy-init="false" class="DataBus" depends-on="PlatformStatusNotifier"/>
So if your client config were to express a dependency on PlatformConnectionDataBus, then that would trigger the initialisation of PlatformConnectionDataBus, which in turn would trigger the initialisation of PlatformStatusNotifier.

Categories