I have multiple processes running on different machines which are required to read/write to a shared XML file, for this I am using DOM with Java and FileLocks (While I know that a database would be a more effective approach, this is not viable due to project constraints) .
To make changes to the XML file, the relevant process first create an exclusively locked channel which is used to read the file, it then attempts to reuse the same channel to write the new version before closing the channel; this way the lock is never down. The issue however is that I am getting a java.nio.channels.ClosedChannelException, even though I never explicitly close the channel. I have suspicions that the line of code:
doc = dBuilder.parse(Channels.newInputStream(channel));
Is what closes the channel (please correct me if I'm wrong!). If so, how could I force the channel to stay open? My code can be seen below:
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 org.w3c.dom.*;
import org.xml.sax.SAXException;
public class Test2{
String path = "...";
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;
try {
channel = new RandomAccessFile(new File(path), "rw").getChannel();
java.nio.channels.FileLock lock = channel.lock(0L, Long.MAX_VALUE, false);
if(lock != null) {
try {
dbFactory = DocumentBuilderFactory.newInstance();
dBuilder = dbFactory.newDocumentBuilder();
doc = dBuilder.parse(Channels.newInputStream(channel));
} 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();
try {
//this.removeBlankTextNodes(doc);
transformer = transformerFactory.newTransformer();
source = new DOMSource(doc);
result = new StreamResult(Channels.newOutputStream(channel));
transformer.setOutputProperty("{http://ift.tt/1fh1NGB", "4");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
doc.getDocumentElement().normalize();
transformer.transform(source, result);
} catch (TransformerException e1) {
e1.printStackTrace();
}
channel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args){
new Test2();
}
}
No comments:
Post a Comment