0

In the manual for ExpressionEvaluatingRequestHandlerAdvice, it clearly says, A typical use case for this advice might be with an <ftp:outbound-channel-adapter/>, perhaps to move the file to one directory if the transfer was successful, or to another directory if it fails.

But I cannot figure out expression to move payload from current directory to another one.

This example just deletes or renames the file:

<bean class="org.springframework.integration.handler.advice.ExpressionEvaluatingRequestHandlerAdvice">
    <property name="onSuccessExpression" value="payload.delete()" />
    <property name="successChannel" ref="afterSuccessDeleteChannel" />
    <property name="onFailureExpression" value="payload.renameTo(new java.io.File(payload.absolutePath + '.failed.to.send'))" />
    <property name="failureChannel" ref="afterFailRenameChannel" />
</bean>

How to achieve this?

Edit

As per Gary's suggestion, this is the new try:

Managed to change the expression to "T(java.nio.file.Files).move(payload.path, new java.io.File(new java.io.File('sent'), payload.name).path, T(java.nio.file.StandardCopyOption).REPLACE_EXISTING)", but still get the error Method move(java.lang.String,java.lang.String,java.nio.file.Standar‌​dCopyOption) cannot be found on java.nio.file.Files type

The code is,

@Bean
    @ServiceActivator(inputChannel = "toSftpChannel", adviceChain = "expressionAdvice")
    public MessageHandler uploadHandler() {
        SftpMessageHandler handler = new SftpMessageHandler(sftpSessionFactory());
        handler.setRemoteDirectoryExpression(new LiteralExpression(outRemoteDirectory));
        handler.setFileNameGenerator(new FileNameGenerator() {

            @Override
            public String generateFileName(Message<?> message) {
                if (message.getPayload() instanceof File) {
                    return ((File) message.getPayload()).getName();
                } else {
                    throw new IllegalArgumentException("File expected as payload.");
                }
            }

        });
        return handler;
    }

    @MessagingGateway()
    public interface UploadGateway {

        @Gateway(requestChannel = "toSftpChannel")
        void upload(File file);

    }

@Bean
    public String onUploadSuccessExpression() {
        return "T(java.nio.file.Files).move(payload.path, new java.io.File(new java.io.File('sent'), payload.name).path, T(java.nio.file.StandardCopyOption).REPLACE_EXISTING)";
    }

@Bean
    public String onUploadFailedExpression() {
        return "payload";
    }

@Bean
    public Advice expressionAdvice() {
        ExpressionEvaluatingRequestHandlerAdvice expressionEvaluatingRequestHandlerAdvice = new ExpressionEvaluatingRequestHandlerAdvice();
        expressionEvaluatingRequestHandlerAdvice.setOnSuccessExpressionString(onUploadSuccessExpression());
        expressionEvaluatingRequestHandlerAdvice.setSuccessChannelName("uploadSuccessChannel");
        expressionEvaluatingRequestHandlerAdvice.setOnFailureExpressionString(onUploadFailedExpression());
        expressionEvaluatingRequestHandlerAdvice.setFailureChannelName("uploadFailedChannel");
        expressionEvaluatingRequestHandlerAdvice.setTrapException(true);
        expressionEvaluatingRequestHandlerAdvice.setPropagateEvaluationFailures(true);
        return expressionEvaluatingRequestHandlerAdvice;
    }

The upload method from UploadGateway is called.

The stack trace is,

"main@1" prio=5 tid=0x1 nid=NA runnable
  java.lang.Thread.State: RUNNABLE
      at org.springframework.integration.handler.advice.ExpressionEvaluatingRequestHandlerAdvice.evaluateSuccessExpression(ExpressionEvaluatingRequestHandlerAdvice.java:241)
      at org.springframework.integration.handler.advice.ExpressionEvaluatingRequestHandlerAdvice.doInvoke(ExpressionEvaluatingRequestHandlerAdvice.java:214)
      at org.springframework.integration.handler.advice.AbstractRequestHandlerAdvice.invoke(AbstractRequestHandlerAdvice.java:70)
      at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
      at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
      at com.sun.proxy.$Proxy81.handleRequestMessage(Unknown Source:-1)
      at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.doInvokeAdvisedRequestHandler(AbstractReplyProducingMessageHandler.java:127)
      at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:112)
      at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:127)
      at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:116)
      at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:148)
      at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:121)
      at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:89)
      at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:423)
      at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:373)
      at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:115)
      at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:45)
      at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:105)
      at org.springframework.messaging.core.AbstractMessageSendingTemplate.convertAndSend(AbstractMessageSendingTemplate.java:143)
      at org.springframework.messaging.core.AbstractMessageSendingTemplate.convertAndSend(AbstractMessageSendingTemplate.java:135)
      at org.springframework.integration.gateway.MessagingGatewaySupport.send(MessagingGatewaySupport.java:392)
      at org.springframework.integration.gateway.GatewayProxyFactoryBean.invokeGatewayMethod(GatewayProxyFactoryBean.java:481)
      at org.springframework.integration.gateway.GatewayProxyFactoryBean.doInvoke(GatewayProxyFactoryBean.java:433)
      at org.springframework.integration.gateway.GatewayProxyFactoryBean.invoke(GatewayProxyFactoryBean.java:424)
      at org.springframework.integration.gateway.GatewayCompletableFutureProxyFactoryBean.invoke(GatewayCompletableFutureProxyFactoryBean.java:65)
      at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
      at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
      at com.sun.proxy.$Proxy87.upload(Unknown Source:-1)
Nets
  • 95
  • 2
  • 11

1 Answers1

0

If the new directory is on the same disk as the old one, in the 'onSuccessExpression', simply use payload.renameTo(...) similar to the way the sample does in the onFailureExpression.

`payload.renameTo(new java.io.File(new File('newDir'), payload.name))`

Creates a file with the payload's name to a directory newDir (which must exist).

If you are JDK 7 or above use...

T(java.nio.file.Files).move(payload.path, new java.io.File(new File('newDir'), payload.name).path)

...instead.

This will handle the situation of the new directory being on a different disk (which a simple File.renameTo() will not).

If you are still on JDK 6 and the new directory might be on a different disk you will need to use onSuccessExpression=payload and subscribe a service activator to the successChannel to manipulate the file itself, perhaps using Spring's FileCopyUtils.

Gary Russell
  • 166,535
  • 14
  • 146
  • 179
  • Thank you very much. I fooled around and managed to work using ServiceActivator and now, will check with 'move'. – Nets Dec 11 '17 at 08:00
  • I tried this but get error, `SpelEvaluationException: A problem occured whilst attempting to construct an object of type 'File' using arguments '(java.lang.String)'` – Nets Dec 11 '17 at 08:08
  • While debugging the application I noticed some possible code errors. Are they bugs or features? 1. In ExpressionEvaluatingRequestHandlerAdvice::evaluateSuccessExpression, the exception is thrown after AdviceMessage is sent to SuccessChannel. This causes Exception payload in it. Shouldn't the method first throw the exception if there is one? 2. In the same class, propagateOnSuccessEvaluationFailures is 'false' by default which causes not to throw Exceptions. That rather negates purpose of FailChannel. I set it to 'true' externally. Can you please explain thought process behind these? – Nets Dec 11 '17 at 08:16
  • Managed to change the expression to `"T(java.nio.file.Files).move(payload.path, new java.io.File(new java.io.File('sent'), payload.name).path, T(java.nio.file.StandardCopyOption).REPLACE_EXISTING)"`´, but still get the error `Method move(java.lang.String,java.lang.String,java.nio.file.StandardCopyOption) cannot be found on java.nio.file.Files type` – Nets Dec 11 '17 at 13:50
  • Don't put extended additional information in comments; it's better to edit the question with more information, then add a short comment to indicate you have done so. I don't understand your point 1. For point 2., generally, an error handler handles the error and there is no need for the caller to know there was a problem. If there is, then generally, the error handler flow should throw a new exception to indicate to the caller the error handler has been involved. The boolean is for the rare instance that you want to handle the error and also throw the original exception to the caller. – Gary Russell Dec 11 '17 at 17:36
  • For your last comment, edit your question to show the current configuration, as well as the stack trace for your exception. I am not at work this week so my answers will be sporadic. – Gary Russell Dec 11 '17 at 17:37
  • Thank you Gary for taking time out of your vacation. I edited the original question as per your suggestion. Currently ServiceActivator works fine but I am curious about 'payload' part. I have created new question about code discussion. https://stackoverflow.com/questions/47771481/expressionevaluatingrequesthandleradvice-sends-message-to-both-success-and-fail – Nets Dec 12 '17 at 11:27