Skip to content

Commit

Permalink
manually clear the inputstream on various XMLInputFactory objects to …
Browse files Browse the repository at this point in the history
…allow gc. Make the code more uniform.

A reference to the last inputstream is kept by the factory, and we keep the factory
in a static reference.

Signed-off-by: HARPER Jon <jon.harper87@gmail.com>
  • Loading branch information
jonenst committed May 19, 2022
1 parent 875c8b4 commit 2c8ee24
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
*/
package com.powsybl.cgmes.model;

import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.powsybl.commons.PowsyblException;
import com.powsybl.commons.exceptions.UncheckedXmlStreamException;
import com.powsybl.commons.xml.XmlUtil;
Expand All @@ -24,6 +26,8 @@
*/
public class FullModel {

private static final Supplier<XMLInputFactory> XML_INPUT_FACTORY_SUPPLIER = Suppliers.memoize(XMLInputFactory::newInstance);

private final String id;

private final ZonedDateTime scenarioTime;
Expand Down Expand Up @@ -138,7 +142,7 @@ public static FullModel parse(Reader reader) {
factory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
factory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");

XMLStreamReader xmlReader = factory.createXMLStreamReader(reader);
XMLStreamReader xmlReader = XML_INPUT_FACTORY_SUPPLIER.get().createXMLStreamReader(reader);
try {
XmlUtil.readUntilStartElement(new String[] {"/", CgmesNames.RDF, CgmesNames.FULL_MODEL}, xmlReader, () -> {
context.id = xmlReader.getAttributeValue(CgmesNamespace.RDF_NAMESPACE, CgmesNames.ABOUT);
Expand Down Expand Up @@ -176,6 +180,7 @@ public static FullModel parse(Reader reader) {
});
} finally {
xmlReader.close();
XmlUtil.gcXmlInputFactory(XML_INPUT_FACTORY_SUPPLIER.get());
}
} catch (XMLStreamException e) {
throw new UncheckedXmlStreamException(e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.powsybl.commons.xml.XmlUtil;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
Expand Down Expand Up @@ -50,6 +51,7 @@ public static Set<String> namespaces1(InputStream is) throws XMLStreamException
}
} finally {
xmlsr.close();
XmlUtil.gcXmlInputFactory(XML_INPUT_FACTORY_SUPPLIER.get());
}
return found;
}
Expand Down
21 changes: 21 additions & 0 deletions commons/src/main/java/com/powsybl/commons/xml/XmlUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
import javanet.staxutils.IndentingXMLStreamWriter;

import javax.xml.stream.*;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
Expand All @@ -20,11 +23,16 @@
import java.util.function.IntConsumer;
import java.util.function.Supplier;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
*/
public final class XmlUtil {

private static final Logger LOGGER = LoggerFactory.getLogger(XmlUtil.class);

private static final Supplier<XMLOutputFactory> XML_OUTPUT_FACTORY_SUPPLIER = Suppliers.memoize(XMLOutputFactory::newFactory);

private XmlUtil() {
Expand Down Expand Up @@ -284,4 +292,17 @@ private static XMLStreamWriter initializeWriter(boolean indent, String indentStr
xmlWriter.writeStartDocument(StandardCharsets.UTF_8.toString(), "1.0");
return xmlWriter;
}

public static void gcXmlInputFactory(XMLInputFactory xmlInputFactory) {
// Workaround: Manually force XMLInputFactory and XmlStreamReader to clear the reference to the last inputstream.
// jdk xerces XmlInputFactory keeps a ref to the last created XmlStreamReader (so that the factory
// can optionally reuse it. But the XmlStreamReader keeps a ref to it's inputstream. There is
// no public API in XmlStreamReader to clear the previous input stream, close doesn't do it).
try (InputStream is = new ByteArrayInputStream(new byte[] {})) {
XMLStreamReader xmlsr = xmlInputFactory.createXMLStreamReader(is);
xmlsr.close();
} catch (XMLStreamException | IOException e) {
LOGGER.error(e.toString(), e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,8 @@ public static Network read(InputStream is, ImportOptions config, Anonymizer anon
checkExtensionsNotFound(context, extensionNamesNotFound);

context.getEndTasks().forEach(Runnable::run);
reader.close();
XmlUtil.gcXmlInputFactory(XML_INPUT_FACTORY_SUPPLIER.get());
return network;
} catch (XMLStreamException e) {
throw new UncheckedXmlStreamException(e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import com.powsybl.commons.config.PlatformConfig;
import com.powsybl.commons.datasource.DataSource;
import com.powsybl.commons.datasource.ReadOnlyDataSource;
import com.powsybl.commons.xml.XmlUtil;
import com.powsybl.iidm.import_.ImportOptions;
import com.powsybl.iidm.import_.Importer;
import com.powsybl.iidm.network.Network;
Expand Down Expand Up @@ -131,6 +132,7 @@ private boolean exists(ReadOnlyDataSource dataSource, String ext) throws IOExcep
} finally {
try {
xmlsr.close();
XmlUtil.gcXmlInputFactory(XML_INPUT_FACTORY_SUPPLIER.get());
} catch (XMLStreamException e) {
LOGGER.error(e.toString(), e);
}
Expand Down

0 comments on commit 2c8ee24

Please sign in to comment.