How to use properties from OSGI/Karaf ConfigurationAdminService with Spring dependency injection - spring

I am trying to inject properties stored in Karaf into my Camel/Spring-Service. So far i tried to inject the properties the way documented in Fuse documentation and Spring.
But both seem outdated: the osgix:cm-properties can't be parsed by current Spring version (Fuse 6.3 uses 3.2.16).
On the other hand Apache Aries seem to have something that could be used now. The aries-blueprint-spring feature contains two bundles:
aries.blueprint.spring
aries.blueprint.spring.extender
I found an old user-list post that points to this bundles. But i can't find any documentation or example using this. We only need to inject the properties.

Have been using OSGi Service Compendium for sometime now and below is some extract from one of my projects, hope it helps.
Important is the declaration of compendium namespace and it's prefix osgix
Also note the declaration of persistent-id as the same has to be defined in Karaf configuration file to be created inside etc directory of your container instance.
Now there is Spring property-placeholder referring to osgix properties declaration and propertyPlaceholder inside CamelContext. Both are required if you want to access properties outside - ${propName} and inside - {{propName}} CamelContext.
To access properties outside Camel Context syntax is ${propertyName}
To access properties inside Camel Context syntnax is {{propertyName}}
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:osgix="http://www.springframework.org/schema/osgi-compendium" xmlns:ctx="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd
http://www.springframework.org/schema/osgi-compendium http://www.springframework.org/schema/osgi-compendium/spring-osgi-compendium.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- A. Configuration Management -->
<osgix:cm-properties id="cachingServicesProp" persistent-id="com.fsafrica.cachingservices.cm">
<prop key="amqBrokerUrl">tcp://localhost:61616</prop>
<prop key="amqUsername">admin</prop>
<prop key="amqPassword">admin</prop>
<prop key="queueName">jms/SRK_CACHE_QUEUE</prop>
</osgix:cm-properties>
<!-- Required for resolving properties for Beans outside CamelContext -->
<ctx:property-placeholder properties-ref="cachingServicesProp" />
<!-- B. ActiveMQ -->
<bean class="org.apache.activemq.camel.component.ActiveMQComponent" id="activemq">
<property name="brokerURL" value="${amqBrokerUrl}" />
<property name="userName" value="${amqUsername}" />
<property name="password" value="${amqPassword}" />
</bean>
<camelContext id="CC-CachingMain" xmlns="http://camel.apache.org/schema/spring">
<!-- Required for resolving properties inside CamelContext -->
<propertyPlaceholder id="properties" location="ref:cachingServicesProp"/>
<!-- JMS INTERFACE -->
<route id="Route-JMSMasterData">
<from uri="activemq:queue:{{queueName}}?transacted=false" />
<log message="#### After putting some data in the Queue (jms/SRK_CACHE_QUEUE) you should be able read this text on Karaf console" />
</route>
</camelContext>
</beans>

Related

Share a Property between two blueprints

I am trying to define a property in blueprint 1 and use it as the default property in blueprint 2.
Both blueprints will be loaded into the same Karaf OSGI container but exist in different bundles. The manifests are already set up with necessary dependency info.
Here is my Blueprint1 that defines the property i want to use again in another blueprint:
<blueprint
xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:osgix="http://www.springframework.org/schema/osgi-compendium"
xsi:schemaLocation="
http://www.osgi.org/xmlns/blueprint/v1.0.0
https://osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
<!-- Properties for this blueprint -->
<osgix:cm-properties id="sharedProperties" persistent-id="com.foo.project" update-strategy="reload"
xmlns="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0">
<default-properties>
<property name="shared-property" value="value"/>
</default-properties>
</osgix:cm-properties>
<bean id="myBean"
class="com.foo.MyClass">
<property name="setting" value="{{shared-property}}"/>
</bean>
And my other Blueprint which is trying to use "my-property" defined above:
<blueprint
xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:osgix="http://www.springframework.org/schema/osgi-compendium"
xmlns:ctx="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.osgi.org/xmlns/blueprint/v1.0.0
https://osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
<!-- Load the properties from Blueprint1. Intent is to use property defined over there, here. -->
<osgix:cm-properties id="sharedProperties" persistent-id="com.foo.project"/>
<!-- Make properties defined in sharedProperties available using ${} syntax-->
<ctx:property-placeholder properties-ref="sharedProperties" />
<!-- Properties for this blueprint -->
<property-placeholder persistent-id="com.foo.project.blueprint2" update-strategy="reload"
xmlns="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0"
placeholder-prefix="{{{"
placeholder-suffix="}}}">
<default-properties>
<property name="my-property" value="${shared-property}"/>
</default-properties>
</property-placeholder>
<bean id="myBean"
class="com.foo.MyClass">
<property name="setting" value="{{{my-property}}}"/>
</bean>
Ive got a feeling(maybe just hope) this is close to correct but off by a little. If it is correct my issue may be with a missing namespace handler.
By using the "default-properties" tag you are redefining the value. Remove the from the second project. Also, I recommend removing default-properties from both and utilize an externalized cfg file so you do not have a race condition at start-up.
Remove this:
<default-properties>
<property name="my-property" value="${shared-property}"/>
</default-properties>

How does spring detects current persistenceUnitName?

I'm working on a spring and JPA project. I had configured my JPA Persistence Unit in the Persistence.xml and here's my spring configuration file.
My application works fine, but I didn't understand how does spring framework detects the Persistence Unit defined in my Persistence.xml file and injects it without being defined in my spring bean configuration file .
Can anybody answer me please ?
<?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"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<context:annotation-config/>
<context:component-scan base-package="ma.professionalpartners.fireAppBusiness.dao"/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="fireApp-Domain" />
</bean>
<bean id="jpaTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="jpaTransactionManager" />
</beans>
You have provided the name for the persistence unit, when configuring the entityManagerFactory bean:
<property name="persistenceUnitName" value="fireApp-Domain" />
The persistence.xml file MUST be on certain paths, so that Spring simply searched in those locations. After finding the file, it parses the XML content, and if there is a single PersistenceUnit, that is made the default one. Of course, if you specify a name (as you did), then it looks exactly for that PersistenceUnit.

Spring config custom namespace

I have a standalone spring application with an embedded Apache FTP server. The config looks like 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:afs="http://mina.apache.org/ftpserver/spring/v1"
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.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://mina.apache.org/ftpserver/spring/v1 http://mina.apache.org/ftpserver/ftpserver-1.0.xsd">
<context:property-placeholder location="classpath:config.properties" system-properties-mode="OVERRIDE"/>
<afs:server id="server" anon-enabled="false">
<afs:listeners>
<afs:nio-listener name="default" port="2222"
idle-timeout="60" />
</afs:listeners>
<!-- other AFS config -->
</afs:server>
</beans>
I would like to load the port property of nio-listener from a properties files, but
<afs:nio-listener name="default" port="${ftp.port}"
idle-timeout="60" />
doesn't work, since port is defined in the xsd as xs:int. I'd like to know if there is any workaround (using SpEL?) that will allow me to use the AFS namespace and load the port property from a file or from system properties.
You could try with PropertyOverrideConfigurer.
The problem is that you need to know the bean name that the <afs:server> tag define (may be 'server') and the property type that <afs:listeners> define (may be a managed list of bean definitions).
Look at STS bean explorer to find correct answers and try whith something like
<context:property-override location="classpath:config.properties" />
server.listeners[0].port=2222
Other option is disable schema validation setting validating to false before refresh in the xml application context.
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
new String[] {"applicationContext.xml"}, false);
context.setValidating(false);
context.refresh();
After exploring a few options, I've decided that the easiest way is to step outside the afs namespace for the just the listener configuration. Final config looks like this -
<bean id="listenerFactory" class="org.apache.ftpserver.listener.ListenerFactory">
<property name="port" value="${ftp.port}" />
<property name="dataConnectionConfiguration">
<bean factory-bean="dataConnectionConfigurationFactory"
factory-method="createDataConnectionConfiguration" />
</property>
</bean>
<bean id="dataConnectionConfigurationFactory" class="org.apache.ftpserver.DataConnectionConfigurationFactory" />
<bean id="nioListener" factory-bean="listenerFactory" factory-method="createListener" />
<afs:server id="server" anon-enabled="false">
<afs:listeners>
<afs:listener name="default">
<ref bean="nioListener"/>
</afs:listener>
</afs:listeners>
<!-- other AFS config -->
</<afs:server>

How can I use Spring Batch Admin with Spring 3.2 and #Schedule annotation?

I integrated Spring Batch Admin into my app, which uses Spring 3.2.
Now I try to annotate a method with #Scheduled and activate this with <task:annotation-driven/>.
When I launch the webapp I get this exception:
Caused by: java.lang.IllegalStateException: #Scheduled method 'removeInactiveExecutions'
found on bean target class 'SimpleJobService', but not found in any interface(s) for bean
JDK proxy. Either pull the method up to an interface or switch to subclass (CGLIB) proxies
by setting proxy-target-class/proxyTargetClass attribute to 'true'
The SimpleJobService of Spring Batch Admin uses this annotation on a method.
In Spring 3.2. it seems, that there is no need to put cglib into the classpath and spring-asm is obsolete, too. I excluded the spring-asm dependency from spring-batch-integration.
Where can I set proxy-target-class=true (I already tried it on <tx:annotation-config> and <aop:config>?
How can I use #Scheduled in my application?
Add execution-context.xml in META-INF\spring\batch\override, set proxy of SimpleJobServiceFactoryBean to target class
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- Original jobRepository missing read ${batch.isolationlevel} -->
<bean id="jobRepository"
class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean"
p:dataSource-ref="dataSource" p:transactionManager-ref="transactionManager" p:isolationLevelForCreate = "${batch.isolationlevel}"/>
<!-- Original jobService conflicted with #EnableScheduling -->
<bean id="jobService"
class="org.springframework.batch.admin.service.SimpleJobServiceFactoryBean">
<aop:scoped-proxy proxy-target-class="true" />
<property name="jobRepository" ref="jobRepository" />
<property name="jobLauncher" ref="jobLauncher" />
<property name="jobLocator" ref="jobRegistry" />
<property name="dataSource" ref="dataSource" />
<property name="jobExplorer" ref="jobExplorer" />
<property name="transactionManager" ref="transactionManager" />
</bean>
</beans>

spring mvc i18n: If key not in properties file, how to set default locale?

suppose if i don't have a key in my one of the properties file i get a exception like :
javax.servlet.ServletException: javax.servlet.jsp.JspTagException: No message found under code 'label.cancel' for locale 'en'.
suppose if it is not available in my messages_ch_CN.properties is there any way that if it is not present in that file it should check in messages_en_En file.
or is there any work around any one has implemented.
For example you have: 2 language
messages_ch_CN.properties /*in the property file lang=Chinese*/
messages_en_EN.properties /*in the property file lang=English*/
messages.properties /*in the property file lang=English default*/
messages.properties this is default property, which always contains every key used throughout your application.
and NAME-servlet.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
<context:component-scan base-package="com.example.controller"/>
<mvc:annotation-driven/>
<mvc:resources mapping="/resources/**" location="/resources/"/>
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:com/example/i18n/messages"/>
<property name="fallbackToSystemLocale" value="false"/>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="lang"/>
</bean>
</mvc:interceptors>
<bean id="localeResolver"
class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
<property name="defaultLocale" value="en"/>
</bean>
</beans>
<property name="fallbackToSystemLocale" value="false"/> - says that, if you don't have property messages_ch_CN.properties or messages_en_EN.properties or in one of those property there is no necessary key, for example: title, spring will use messages.properties as default
if <property name="fallbackToSystemLocale" value="true"/> - spring uses user locale of deployment environment, but it not good because user's deployment environment, can different from the languages that we have provided. If user's locale different from the languages that we have provided, spring uses messages.properties.
One workaround would be to subclass the messageSource you're using (ie ReloadableResourceBundleMessageSource) and override it's resolveCode() so that:
it looks for a message for specified code and locale (by calling super.resolveCode(code, locale)).
if it doesn't find it, then it looks for one with default locale (by calling super.resolveCode(code, defaultLocale)).
Then use that newly created class as messageSource.
Always provide a default messages file (without locale specification), which always contains every key used throughout your application. It is not possible to look automatically for another locale than the chosen one without subclassing one of the ResourceBundleimplementations.

Resources