如何确定 JAXB 已完成编组到文件

How to determine that JAXB is done marshalling to file

在服务器上有一个进程每隔特定时间间隔(比如 5 分钟)从特定目录中获取文件。 正在拾取的文件是由网络服务生成的。 JAXB 编组将文件从对象转换为 xml 文件。 问题是文件在完成之前被拾取的情况经常发生。 一个解决方案是将文件放在一个临时目录中,或者给它们一个临时的特定扩展名,让轮询过程知道要跳过这些文件。 之后可以将文件移动到处理目录或更改扩展名,以便轮询进程可以提取它们。

方法如下所示;

    private void writeToFile(Object obj, String outputFileName) {
    LOG.debug("Executing operation writeToFile using filename '{}' and object of type '{}'.", outputFileName, obj.getClass());

    try {
        Marshaller jaxbMarshaller = JAXB_CONTEXT.createMarshaller();
        jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        jaxbMarshaller.marshal(obj, new File(outputFileName));
        LOG.debug("Wrote request to file '{}'.", outputFileName);
    } catch (JAXBException e) {
        LOG.error("Exception occurred while writing request to file:", e);
    }
    LOG.debug("Done executing operation writeToFile.");
}

我的问题是确定编组过程是否已完成以便可以释放文件以进行进一步处理?

这是一些代码,我是如何解决的(Spring 集成)

您创建一个缓冲区来存储不够旧的文件并稍后处理它们。

我知道它并不完美(睡眠),但它确实有效。更好的解决方案不是使用文件交换,而是使用 REST-api 传输数据。

import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.integration.core.MessageSource;
import org.springframework.messaging.Message;

import java.io.File;
import java.util.List;

public class LastModifiedFileReadingMessageSource implements MessageSource<File> {

    private final Logger log = LoggerFactory.getLogger(LastModifiedFileReadingMessageSource.class);
    private final MessageSource fileReadingMessageSource;
    private final List<Message<File>> buffer = Lists.newArrayList();
    private final long age = 60;

    public LastModifiedFileReadingMessageSource(MessageSource fileReadingMessageSource) {
        this.fileReadingMessageSource = fileReadingMessageSource;
    }

    public Message<File> receive() {
        Message<File> message = fileReadingMessageSource.receive();
        while (message != null) {
            if (isOldEnough(message)) {
                return message;
            } else {
                buffer.add(message);
                log.info("Buffering file which is not old enough: {}; Buffer size: ", message, buffer.size());
            }
            message = fileReadingMessageSource.receive();
        }
        while (!buffer.isEmpty()) {
            message = buffer.stream().filter(this::isOldEnough).findFirst().orElse(null);
            if (message != null) {
                buffer.remove(message);
                log.info("Use file from buffer: {}; Buffer size: ", message, buffer.size());
                return message;
            }
            sleep();
        }
        return message;
    }

    private void sleep() {
        try {
            log.info("Go to sleep for a while... ({} seconds)", age);
            Thread.sleep(this.age * 1000);
        } catch (InterruptedException e) {
            log.error("Thread.sleep was never a good idea ;(", e);
        }
    }

    private boolean isOldEnough(Message<File> message) {
        long now = System.currentTimeMillis() / 1000;
        return (message.getPayload().lastModified() / 1000 + this.age <= now);
    }
}

请从这里下载代码 link [https://turreta.com/2017/03/07/jaxb-perform-pre-and-post-processing-with-unmarshaller-listener/] 将下面的 Person Marshall Listener 代码添加到源代码中,因为每个节点都将调用此代码检查了 Person 中的根 Node 实例(这需要修改为你的基本节点)在马歇尔方法之前和之后,也使用了 2 的计数,因为开始和结束节点每次都调用它,因为这应该只在结束节点检查时调用,如果计数 == 2

package com.turreta.jaxb.unmarshaller.listener;

    public class PersonMarshallListener extends javax.xml.bind.Marshaller.Listener {

            int beforeCount = 1;
            int afterCount = 1;

          @Override
           public void beforeMarshal(Object source) {
              super.beforeMarshal(source);
              if (source instanceof Person) {

                  if (beforeCount == 2) {
                      beforeCount = 1;
                      System.out.println("BEFORE MARSHAL");
                  } else {
                      beforeCount++;
                  }
              }

           }

           @Override
           public void afterMarshal(Object source) {
               super.afterMarshal(source);

               if (source instanceof Person) {

                   if (afterCount == 2) {

                       afterCount = 1;
                       System.out.println("AFTER MARSHAL");
    //                 System.out.println("This will be called once the marshall has been completed");
                   } else {
                       afterCount++;
                   }
               }


           }

    }

并用以下代码替换DemoApp

package com.turreta.jaxb.unmarshaller.listener;

import java.io.FileInputStream;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;

public class DemoApp {
    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Person.class);

        XMLInputFactory xif = XMLInputFactory.newFactory();
        FileInputStream xml = new FileInputStream("src/main/resources/person.xml");
        XMLStreamReader xsr = xif.createXMLStreamReader(xml);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        PersonUnmarshallListener pul = new PersonUnmarshallListener();
        unmarshaller.setListener(pul);

        Person person = (Person) unmarshaller.unmarshal(xsr);
        System.out.println(person);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setListener(new PersonMarshallListener());
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(person, System.out);


    }
}