SourcePollingChannelAdapter create - java

I use spring and spring-integration. I need create SourcePollingChannelAdapter dynamic for Feed parse, and register in Spring context.
QueueChannel channel = (QueueChannel) context.getBean("rssFeedChannel");
SourcePollingChannelAdapter adapter = new SourcePollingChannelAdapter();
adapter.setApplicationContext(context);
adapter.setBeanName("adapter.1");
FeedEntryMessageSource source = new FeedEntryMessageSource(new URL("https://spring.io/blog.atom"), "news");
source.setApplicationContext(context);
source.setBeanName("source");
adapter.setSource(source);
adapter.setOutputChannel(channel);
adapter.setTrigger(new PeriodicTrigger(1000));
adapter.start();
And my application config:
<int:poller default="true" fixed-rate="5000"/>
<int:channel id="rssFeedChannel">
<int:queue capacity="40"/>
</int:channel>
<file:outbound-channel-adapter id="file" mode="APPEND" charset="UTF-8" directory="/tmp/si" filename-generator-expression="'SpringBlog'"/>
<!-- With this work -->
<!--<feed:inbound-channel-adapter id="news" channel="rssFeedChannel" url="https://spring.io/blog.atom">-->
<!--<int:poller fixed-rate="5000"/>-->
<!--</feed:inbound-channel-adapter>-->
<int:transformer input-channel="rssFeedChannel" expression="payload.title + ' # ' + payload.link + '#{systemProperties['line.separator']}'" output-channel="file"/>
but nothing is written to the file. Please help bug.

You must make FeedEntryMessageSource as bean, too. The applicationContext injection.
You forgot to invoke adapter.afterPropertiesSet(). BTW the same for the FeedEntryMessageSource instance.
From other side, please, share what is in your mind for the reason to go this manual way. Why just don't rely on the standard Inversion of Control principle?

Related

How to open/close Spring Integration channel based on environmental variable?

I have a channel that is used as input-channel in a chain. I need to use it only when the environmental variable sd is not true. Is it possible to write this condition into the spring-integration file without creating an additional Java filter? So, I would like this chain not to work when -Dsd=true in the startup script and work in any other case.
<int:channel id="sdCreationChannel">
<int:queue/>
</int:channel>
<int:chain input-channel="sdCreationChannel" output-channel="debugLogger">
<int:poller fixed-delay="500" />
<int:filter ref="sdIntegrationExistingRequestSentFilter" method="filter"/>
<int:transformer ref="sdCreationTransformer" method="transformOrder"/>
<int:service-activator ref="sdCreationServiceImpl" method="processMessage">
<int:request-handler-advice-chain>
<ref bean="retryAdvice"/>
</int:request-handler-advice-chain>
</int:service-activator>
</int:chain>
The <chain> is a normal endpoint which can be started/stopped according it lifecycle contract.
So, you can start/stop it by its id at runtime at any time or with any condition.
Another trick that it is just enough to add auto-startup="false" to its definition based on that variable.
M-m-m. I think that should work even with normal property-placeholder:
<int:chain auto-startup="${myChain.autoStartup}">
From other side you can take a look to the profile feature and configure it like this:
<beans profile="myChain.profile">
<int:chain>
....
</int:chain>
</beans>
UPDATE
According to your concern:
So, I would like this chain not to work when -Dsd=true in the startup script and work in any other case
As I said above: you can just only mark it in auto-startup="false" from the beginning, for example using the same Environment:
<int:chain auto-startup="#{environment.getProperty('sd', true)}">

dynamically determining polling frequency in mule

I have been struggling to find a work around to be able to dynamically read the polling frequency in mule flow. Currently I am reading that from a file using spring's Propertyplaceholder at the start up and value remains the same even if the fie is changed(as we all know)..
Since poll tag needs to be the first component in the flow, There is nothing much i could do to read the "live" file update.
Is there any way I could set the polling frequency dynamically read from a file(without requiring restart)?
For Reference:
<spring:beans>
<context:property-placeholder location="file:///C:/Users/test/config.properties" />
</spring:beans>
<flow name="querying-database-pollingFlow1" doc:name="querying-database-pollingFlow1">
<poll doc:name="Poll3e3">
<fixed-frequency-scheduler frequency="${pollinginterval}"/>
<db:select config-ref="MySQL_Configuration1" doc:name="Perform a query in MySQL">
<db:dynamic-query><![CDATA[select empId,empName from employer where status='active';]]></db:dynamic-query>
</db:select>
</poll>
....</flow>
There is absolutely no issue with <fixed-frequency-scheduler frequency="${pollinginterval}"/> as you can dynamically read polling frequency from a properties file ...
The only thing I am concern here is :- <context:property-placeholder location="file:///C:/Users/test/config.properties" />
Since you are reading from a properties file outside your classpath, better try with the following :-
<context:property-placeholder
location="file:C:/Users/test/config.properties" />
One more thing .. if you are using Spring beans for properties file use the following way :-
<spring:beans>
<spring:bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<spring:property name="locations">
<spring:list>
<spring:value>file:C:/Users/test/config.properties</spring:value>
</spring:list>
</spring:property>
</spring:bean>
</spring:beans>
The clean way using FixedFrequencyScheduler is not there. You could potentially go to the registry, fetch your flow by name, then get the MessageSource and cast it to FixedFrequencyScheduler set the new interval and stop-start, however if you take a look to the code you'll see there is no setter for it and reflexion it's just too dirty.
My first choice would probably be to leverage a quartz endpoint and then leverage the quartz abilities to expose the configuration throught jmx/rmi.
I would definitely advise against using hot deploy to solve this problem especially if you need to change the frequency often. There is a risk that this will lead to problems with permgen running out of memory.
Instead you could use a flow with a quartz endpoint that fires at a relatively low frequency. Then add a filter that only lets through the message at the required frequency.
The filter can either watch a properties file for changes or expose attributes over JMX to allow you to change the frequency. Something like this.
<spring:beans>
<spring:bean id="frequencyFilter" class="FrequencyFilter" />
</spring:beans>
<flow name="trigger-polling-every-second" doc:name="trigger-polling-every-second">
<quartz:inbound-endpoint repeatInterval="1000" doc:name="Quartz" responseTimeout="10000" jobName="poll-trigger">
<quartz:event-generator-job>
<quartz:payload>Scheduled Trigger</quartz:payload>
</quartz:event-generator-job>
</quartz:inbound-endpoint>
<filter ref="frequencyFilter" />
<vm:outbound-endpoint path="query-database" />
</flow>
<flow name="query-database">
<vm:inbound-endpoint path="query-database" />
<db:select config-ref="databaseConfig" doc:name="Perform a query in database">
<db:dynamic-query><![CDATA[select empId,empName from employer where status='active']]></db:dynamic-query>
</db:select>
<logger level="ERROR" message="#[payload]"/>
</flow>

Spring AMQP: Queue with machine name

I'm working with Spring AMQP to create queues in RabbitMQ. I'd like to have a queue whose name includes the name of the machine that the app is running on. So the queue name might be "fooQueue.host1" or "fooQueue.host2" depending on where you run the app.
I've figured out a way to do this (detailed below) but it seems a little complicated. Is there an easier/better/Spring-ier way to accomplish this?
My Solution
First make a bean to fetch the machine name:
public class MachineNamePropertyBean {
public String GetMachineName() throws UnknownHostException {
InetAddress localMachine = InetAddress.getLocalHost();
return localMachine.getHostName();
}
}
Then register the bean in your Spring config:
<bean id="machineNameBean" class="com.example.myapp.MachineNamePropertyBean" />
then use it in your Spring AMQP config like this:
<rabbit:queue id="fooQueue"
name="fooQueue.#{ machineNameBean.GetMachineName() }"
durable="false"
auto-delete="false"
exclusive="false" />
There is no other solution unless using SpEL:
<bean id="machineName" class="java.lang.String">
<constructor-arg value="#{T(java.net.InetAddress).localHost.hostName}"/>
</bean>
<rabbit:queue id="fooQueue"
name="fooQueue.#{ machineName }"
durable="false"
auto-delete="false"
exclusive="false" />
The same as you are doing, but without new class and via SpEL features.

Spring RabbitMQ - is a queue configuration with no exchanges possible

Here is an existing spring rabbit config from a project that I inherited -
<rabbit:connection-factory id="rabbitConnectionFactory"
host="${rabbitmq.host}"
port="${rabbitmq.port}"
virtual-host="${rabbitmq.virtualHost}"
username="${rabbitmq.username}"
password="${rabbitmq.password}"/>
<rabbit:template id="ampqTemplate" connection-factory="rabbitConnectionFactory" routing-key="" />
<rabbit:admin connection-factory="rabbitConnectionFactory" />
<rabbit:queue name="${rabbitmq.queueName}" />
I dont have experience using Rabbit and with my limited reference,
I understand an exchange is an important piece in the setup since it relays messages to the queue internally.
However, the above configuration does not contain any exchange information.
My Questions are :
Is an exchange absolutely important for even a simple queue configuration.?
Is there any implication of not defining an exchange
Is there anyother configuration obviously missing from the above configuration?
If you don't define an exchange the default exchange will be used. It is a direct exchange which will use the name of the queue as its routing key.
It doesn't look like there is anything missing from your configuration. Mine is:
<rabbit:connection-factory id="connectionFactory" host="${rabbit.host}" username="${rabbit.username}" password="${rabbit.password}" virtual-host="${rabbit.vhost}"/>
<rabbit:template id="rabbitTemplate" connection-factory="connectionFactory" message-converter="jsonMessageConverter" routing-key="event-queue"/>
You may be able to take the rabbit:queue definition out and use the queue name as the routing key for the rabbit:template.

calling methods in Spring configurations

I am tying to migrate hard coded database dependencies into the spring framework
so
Mongo m = new Mongo("192.168.0.0.1");
DB db = m.getDB("db name");
db.authenticate("user", "pass".toCharArray());
would become:
<mongo:mongo host="192.168.0.0.1" port="27017" />
<bean id="mongoDatabase"
factory-bean="mongo"
factory-method="getDB">
<constructor-arg value="db name" />
</bean>
But I am not sure how to call authenticate. It would be nice to know the best way to do this generally.
(Usernames and passwords have been changed to protect the innocent)
You can use <mongo:db-factory>.

Categories

Resources