Write to an XML file at the same time

I have several processes running on different machines that are necessary for reading / writing to a common XML file, for this I use DOM with Javaand FileLocks(Although I know that a database will be a more efficient approach, this is impractical due to project limitations).

To make changes to the XML file, the corresponding process first creates an exclusively locked channel that is used to read the file, then it tries to reuse the same channel to write a new version before closing the channel; thus the castle never falls. However, the problem is what I get java.nio.channels.ClosedChannelExceptionwhen I try to record the result, although I never explicitly close the channel. I have a suspicion that the line of code is:

doc = dBuilder.parse(Channels.newInputStream(channel));

closes the channel. If so, how can I make the channel stay open? My code can be seen below:

[remote code after update]

UPDATE: Placing System.out.println(channel.isOpen())before and after the suspicious line of code confirms that the channel is closed here.

UPDATE: By asking a separate question , the code below prevents the channel from closing during the parsing operation. The problem is that instead of replacing the original XML file, the transformer adds the modified document to the original. In the documentation, I cannot find any related options to indicate the output Transformer.transform(I was looking for Transformer/ Transformer factory/ StreamResult). Am I missing something? Do I need to somehow clear the channel before writing? Thank.

: , , 0. @JLRishe . .

+1
2

, , , ! . .

import java.io.*;
import java.nio.channels.*;

import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.*;

import org.w3c.dom.*;
import org.xml.sax.SAXException;

public class Test2{ 
    String path = "...Test 2.xml";

    public Test2(){
        Document doc = null;
        DocumentBuilderFactory dbFactory;
        DocumentBuilder dBuilder;
        NodeList itemList;
        Transformer transformer;
        FileChannel channel; 
        Element newElement;
        int prevNumber;
        TransformerFactory transformerFactory ;
        DOMSource source;
        StreamResult result;
        NonClosingInputStream ncis = null;
        try {
            channel = new RandomAccessFile(new File(path), "rw").getChannel();
            FileLock lock = channel.lock(0L, Long.MAX_VALUE, false);

            try {
                dbFactory = DocumentBuilderFactory.newInstance();
                dBuilder = dbFactory.newDocumentBuilder();
                ncis = new NonClosingInputStream(Channels.newInputStream(channel));
                doc = dBuilder.parse(ncis);
            } catch (SAXException | IOException | ParserConfigurationException e) {
                e.printStackTrace();
            }
            doc.getDocumentElement().normalize();
            itemList = doc.getElementsByTagName("Item");
            newElement = doc.createElement("Item");
            prevNumber = Integer.parseInt(((Element) itemList.item(itemList.getLength() - 1)).getAttribute("Number"));
            newElement.setAttribute("Number", (prevNumber + 1) + "");

            doc.getDocumentElement().appendChild(newElement);

            transformerFactory = TransformerFactory.newInstance();
            transformer = transformerFactory.newTransformer();
            source = new DOMSource(doc);
            channel.truncate(0);
            result = new StreamResult(Channels.newOutputStream(channel));   

            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
            transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
            transformer.setOutputProperty(OutputKeys.METHOD, "xml");
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
            transformer.transform(source, result);
            channel.close();
        } catch (IOException | TransformerException e) {
            e.printStackTrace();
        } finally {
            try {
                ncis.reallyClose();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    class NonClosingInputStream extends FilterInputStream {

        public NonClosingInputStream(InputStream it) {
            super(it);
        }

        @Override
        public void close() throws IOException {
            // Do nothing.
        }

        public void reallyClose() throws IOException {
            // Actually close.
            in.close();
        }
    }

    public static void main(String[] args){
        new Test2();
    }
}
0

:

  • (), " ".
  • , " " .

, . , , , .

( ). , .

0

Source: https://habr.com/ru/post/1695896/


All Articles