The following is my configuration xml for a file polling functionality. I have to change the output directory sometimes.
<int-file:inbound-channel-adapter id="filesIn" directory="file:${paths.root}" channel="abc" >
<int:poller id="poller" fixed-delay="5000"/>
</int-file:inbound-channel-adapter>
<int:channel id="abc"/>
<int-file:outbound-channel-adapter channel="abc" id="filesOut"
directory-expression="#aPath.getPath()"
delete-source-files="true"
filename-generator ="filenameGenerator"/>
<bean id="filenameGenerator" class="com.dms.util.FileNameGenerator"/>
In the
#Override
public String generateFileName(Message<?> message)
{
I have tried setting the value of a configured bean property.
This is the additional configuration for that
<bean name="aPath" class="com.dms.util.GetOutPath">
<property name="path" value="${paths.destination}"/>
</bean>
paths.destination is from a property file.
In the generateFileName method I have added the code for changing the property value as follows
#Autowired
private GetOutPath outPathBean;
For the bean:
#Component("outPathBean")
and in my code
outPathBean.setPath(newFolder);
My debugging shows that the value of the property does not change. My question is, How do I modify the directory either in the generateFileName method or by any other way.
Please help!
The general mechanism you are trying to use will work because the file name generator is calle before evaluating the directory expression.
However, you have two instances of you really have the #Component defined (and you are using component scanning, you will have two instances of GetOutPath - aPath and outPathBean.
The expression is using the instance that you are not changing.
You need to inject the same bean instance that you are using in your expression.
Related
I'm currently working with citrus-framework to test an application.
One of my interfaces uses Protobuf and I would like to implement a protobuf-to-json-transformer which is compatible with spring-integration to use it similarly like the following but with my transformer instead of the object-to-string-transformer:
<int:channel id="configRawReplies" />
<int:object-to-string-transformer id="configtransformer" input-channel="configRawReplies" output-channel="configResponse" />
<int:channel id="configResponse">
<int:queue />
</int:channel>
for now I have a prototyp exactly like object-to-string-transformer and I'm loading it with:
<bean id="Proto2Json" class="com.nobody.citrus.transformer.ProtoToJSONString">
<property name="input-channel" value="none"/>
<property name="output-channel" value="none"/>
</bean>
but it fails.
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'Proto2Json' defined in URL [file:/Users/nobody/DevOops/test/citrus-scala/target/test-classes/citrus-context.xml]:
Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException:
Invalid property 'input-channel' of bean class [com.pme.citrus.transformer.ProtoToJSONString]:
Bean property 'input-channel' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
Does somebody have an idea or an hint where to look on the web?
BR
That's correct. You really need to follow a design in the ObjectToStringTransformer to implement your own AbstractPayloadTransformer. And that one has to be as a plain <bean> definition in your application context.
Only the problem that you don't understand why we really have all those custom tags to utilize input-channel and output-channel attributes as well. The point is that this
<int:object-to-string-transformer>, for example, provides for the application context several beans, including the mentioned ObjectToStringTransformer instance, a MessageTransformingHandler and, finally, ConsumerEndpointFactoryBean to connect a MessageHandler with an inputChannel.
So, what you are missing here is a generic <int:transformer> definition for your custom AbstractPayloadTransformer implementation:
<bean id="Proto2Json" class="com.nobody.citrus.transformer.ProtoToJSONString"/>
<int:tranformer ref="Proto2Json" input-channel="configRawReplies" output-channel="configResponse"/>
Please, read more Reference Manual to avoid similar discussions in the future:
https://docs.spring.io/spring-integration/reference/html/overview.html#programming-tips
https://docs.spring.io/spring-integration/reference/html/messaging-transformation-chapter.html
In my application i have a router that dinamically send XML tag to the appropiate channel:
<!-- Route each tag to the appropiate channel -->
<int-xml:xpath-router id="router" input-channel="routerChannel" evaluate-as-string="true">
<int-xml:xpath-expression expression="concat(name(./node()), 'Channel')" />
</int-xml:xpath-router>
Using this XML this route each tag to serviceChannel and activityChannel
<root>
<service attr1="x" attr2="y" />
<activity anotherAttr="W" />
</root>
My service activator(S) POJO are something like this:
class Service {
private String attr1;
private String attr2;
/* Setter and getter omitted */
}
And this is the applicationContext.xml configuration:
<!-- Service activators -->
<int:service-activator input-channel="serviceChannel" method="schedule">
<bean class="it.mypkg.Service" />
</int:service-activator>
The router send the entire Node to bean and i will need to extract the attributes "by hand".
There is a way to "unmarshall" the Node so in attr1 and attr2 i will get the value provided in XML ?
Usally i do this with a simple Unmarshaller (using JAXB) and adding the annotations #XmlRootElement, #XmlAttribute and so on.
I think before pass to POJO i will need to use SI-XML UnmarshallingTransformer but i really dont know how to do this... moreover this should be "enough general" to handle all tags (sure, all POJO classes like Service and Activity will have #XmlAttribute etc)
Use an Unmarshalling Transformer and then route on the unmarshalled objects.
Using XML configuration - I have MarshallingMessageConverter working; however, I still want to send some messages as TextMessage with simple String values.
It seems that my configuration is forcing me to go from one ditch (No automatic JAXB marshalling) into the other (JAXB marshalling only):
Here's my relevant XML configuration:
<bean id="jaxbConverter" class="org.springframework.jms.support.converter.MarshallingMessageConverter">
<property name="marshaller" ref="jaxb2Marshaller" />
<property name="unmarshaller" ref="jaxb2Marshaller" />
</bean>
<bean id="jmsListenerContainerFactory"
class="org.springframework.jms.config.DefaultJmsListenerContainerFactory">
<property name="errorHandler" ref="jmsErrorHandler" />
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destinationResolver" ref="jmsDestinationResolver"/>
<property name="messageConverter" ref="jaxbConverter" />
</bean>
The JAXB marshalling works fine, but I sometimes want to send an empty body (header properties only) message; which causes an error like so:
.UnmarshallingFailureException: JAXB unmarshalling exception; nested exception is javax.xml.bind.UnmarshalException
- with linked exception:
[org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Content is not allowed in prolog.]
Which makes sense, because I'm sending a non-JAXB string (or nothing) in the body.
Is it possible to have the best of both worlds; the String, byte[], Map conversion behavior of org.springframework.jms.support.converter.SimpleMessageConverter -and- org.springframework.jms.support.converter.MarshallingMessageConverter ?
Is the only way to accomplish this by making a second container factory with the other converter and explicitly using it in my #JmsListener annotation?
Create a simple DelegatingMessageConverter(implement MessageConverter) and have it delegate to the SimpleMessageConverter, MarshallingMessageConverter (or even a MappingJackson2MessageConverter) based on a message property, e.g. message.getStringProperty("contentType") - text/plain, application/xml, application/json.
I have an scenario where I must send messages in order to a rest service and I plan to use a resequencer. The behaviour of this resequencer must be:
Order messages by time in day (hh:mm:ss): data on the message
Release messages only after they stay a period of time in the bus (p.e. 2 minutes)
As the default Resequencer didn't serve for this purpose I decided to develop a custom one changing the ResequencerMessageGroupProcessor for a CustomResequencerMessageGroupProcessor.
I succeded using a service activator but I had to explictly define the output-channel as a property. Isn't there a way to use the output-channel attribute on the xml declaration?
When I use the output-channel attribute the following error occurs:
Caused by: java.lang.IllegalArgumentException: no outputChannel or replyChannel header available
at org.springframework.util.Assert.notNull(Assert.java:112)
at org.springframework.integration.aggregator.AbstractCorrelatingMessageHandler.sendReplies(AbstractCorrelatingMessageHandler.java:616)
at org.springframework.integration.aggregator.AbstractCorrelatingMessageHandler.completeGroup(AbstractCorrelatingMessageHandler.java:597)
at org.springframework.integration.aggregator.AbstractCorrelatingMessageHandler.handleMessageInternal(AbstractCorrelatingMessageHandler.java:405)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:78)
... 46 more
here's my example:
<int:channel id="resequencerChannel"/>
<int:service-activator id="customResequencer" ref="resequencingMessageHandler"
input-channel="resequencerChannel" />
<int:channel id="aggregatedMessageChannel" />
<bean id="resequencingMessageHandler" class="org.springframework.integration.aggregator.ResequencingMessageHandler">
<constructor-arg name="releaseStrategy" ref="timeoutReleaseStrategy"/>
<constructor-arg name="processor" ref="customResequencerMessageGroupProcessor"/>
<constructor-arg name="store" ref="redisMessageStore"/>
<constructor-arg name="correlationStrategy" ref="customCorrelationStrategy"/>
<property name="outputChannel" ref="aggregatedMessageChannel"/>
<property name="sendPartialResultOnExpiry" value="true"></property>
</bean>
<bean id="customResequencerMessageGroupProcessor" class="test.resequencer.CustomResequencerMessageGroupProcessor">
<constructor-arg name="timeout" value="10000"/>
</bean>
<bean id="timeoutReleaseStrategy" class="org.springframework.integration.aggregator.TimeoutCountSequenceSizeReleaseStrategy" >
<constructor-arg name="threshold" value="100000"></constructor-arg>
<constructor-arg name="timeout" value="10000"/>
</bean>
<bean id="customCorrelationStrategy" class="org.springframework.integration.aggregator.HeaderAttributeCorrelationStrategy" >
<constructor-arg name="attributeName" value="correlationId"/>
Also, if you think there is a better way to do this, please, I would apreciatte telling so
Thanks in advance!
Regards
Guzman
When referencing (ref) a MessageHandler from a <service-activator/> the XML output-channel is only applied if the referenced handler is an AbstractReplyProducingMessageHandler (ARPMH).
Components such as routers, aggregators, resequencers, are not considered to be ARPMHs because they sometimes produce a reply, sometimes don't and, in the case of a router, might produce multiple "replies" which doesn't fit the service activator model.
We could probably refactor the aggregator/resequencer to be ARPMHs because they only produce 0 or 1 "reply". We could also add some smarts to the ServiceActivatorFactoryBean to inject the output channel if the reference is an AbstractCorrelatingMessageHandler. Feel free to open an Improvement JIRA Issue.
In the meantime, your solution is the correct work-around.
How do you get a reference to the current ActivePivotManger? I've found code that uses it but no way to actually get ahold of it.
If you look at the class SandboxConfig in last v4.4.x you'll see that this class is annotated as following:
#PropertySource(value="classpath:sandbox.properties")
#Configuration
#Import(value={
ActivePivotConfig.class,
ActivePivotServicesConfig.class,
WebServicesConfig.class,
RemotingConfig.class,
SecurityConfig.class
})
public class SandboxConfig {
The ActivePivotConfig.class in the annotation is the one in which we define the activePivotManager which is defined as a member of the SandboxConfig class:
/** ActivePivot Manager, automatically wired */
#Autowired
protected IActivePivotManager activePivotManager;
The #Autowired here is important as it means that this is provided already.
in the previous versions of AP we were defining this as following in our project:
<!-- ActivePivot Manager -->
<bean id="ActivePivotManager" class="com.quartetfs.biz.pivot.impl.ActivePivotManagerFactory">
<property name="resourceName" value="DESC-INF/ActivePivotManager.xml" />
<property name="autoStart" value="false" />
<property name="healthCheckPeriod" value="120"/>
</bean>
If you want to use the ActivePivotManager instance stick then to what is in the SandboxConfig and add your logic there, use the ActivePivotManager instance defined there.
If you're not happy with that move to full XML wiring which is still supported as I can understand that some stuff is hidden and you expect to see the instance of ActivePivotManager instantiated clearly somewhere (which is done actually in ActivePivotConfig.class).