Spring config custom namespace - spring

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>

Related

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

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>

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>

In Spring/Tomcat, which configuration file do jndi lookups refer to?:

I'm having trouble getting a Spring/Tomcat app to resolve a variable which appears as a property of a JndiFactoryObjectName bean in the application context. Here's the relevant bean entry:
When I try to run it on the server, it comes up with this error:
Caused by: javax.naming.NameNotFoundException: Name search.url is not bound in this Context
This entry in server.xml doesn't seem to help:
There's also an entry in (as seen from Eclipse/STS)
Tomcat v6.0 Server at localhost
Catalina
localhost
ROOT.xml
<Context path="" reloadable="true" docBase="C:/myworkspace32/myAppName/WebContent">
<ResourceLink global="search.url" name="search.url" type="java.lang.String"/>
</Context>
However, this seem to have no impact.
Here are the steps to access JNDI resource from tomcat
Create jndi resource in server.xml
<Resource global="search.url" name="search.url" type="java.lang.String" />
Create the link in context.xml so that its accessible by all the web application.
<ResourceLink name="search.url" global="search.url" auth="Container" type="java.lang.String" />
Use spring bean or jee tag to inject the jndi
<bean id="searchUrl" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/search.url"/>
</bean>
you can avoid specify the environment by using jee contatiner tag as follows
<jee:jndi-lookup id="searchUrl" jndi-name="search.url" expected-type="java.lang.String" />
Follow an example of Tomcat JNDI with Spring
Spring configuration
<?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:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<jee:jndi-lookup id="yourDS" jndi-name="java:comp/env/yourDS"/>
Tomcat configuration (put this in ${catalina.home}\conf\context.xml)
<Resource
name="yourDS"
type="javax.sql.DataSource"
username="****"
password="*****"
driverClassName="com.ibm.db2.jcc.DB2Driver"
url="*******"
maxActive="8"
maxIdle="4"
/>

Spring systemProperties not appending value properly

I am using Spring 3.1 to create a bean in an web application like below wherein the server contains -DCONFIG_MODE=dev. However, it seems spring is only resolving the filename to configuration.dev without appending the remaining .xml. Could you please point what could be wrong in 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:ws="http://jax-ws.dev.java.net/spring/core"
xmlns:wss="http://jax-ws.dev.java.net/spring/servlet"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://jax-ws.dev.java.net/spring/core http://jax-ws.dev.java.net/spring/core.xsd
http://jax-ws.dev.java.net/spring/servlet http://jax-ws.dev.java.net/spring/servlet.xsd">
<bean id="xmlConfig" class="org.quwic.itms.mq.XmlConfiguration" init-method="init">
<constructor-arg type="java.net.URL" value="classpath:configuration.#{systemProperties.CONFIG_MODE}.xml"/>
<constructor-arg type="org.apache.commons.configuration.reloading.ReloadingStrategy" ref="reloadingStrategy"/>
</bean>
<!-- The managed reloading strategy for the configuration bean -->
<bean id="reloadingStrategy" class="org.apache.commons.configuration.reloading.FileChangedReloadingStrategy">
<property name="refreshDelay" value="300000"/>
</bean>
</beans>
Thanks,
Fixed it. I wrongly specified the system property as "-DCONFIG_MODE=local -Dprogram.name=JBossTools: JBoss 5.0 Runtime" rather than -DCONFIG_MODE=local "-Dprogram.name=JBossTools: JBoss 5.0 Runtime"

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>

Resources