package org.jboss.windup.rules.apps.xml.model; import java.lang.ref.SoftReference; import java.util.HashMap; import java.util.Map; import java.util.logging.Logger; import org.jboss.windup.util.Logging; import org.w3c.dom.Document; /** * This class provides a cache for parsed XML documents, using {@link SoftReference}s in order to avoid creating unnecessary memory pressure. */ public class XMLDocumentCache { private static final Logger LOG = Logging.get(XMLDocumentCache.class); private static final Map<String, CacheDocument> map = new HashMap<>(); /** * This is used to pass data back to the caller regarding the cache search. * * If a parsing failure had been cached, {@link Result#isParseFailure()} will return true, and {@link Result#getDocument()} will return false. * * A cache miss will have {@link Result#isParseFailure()} set to false and {@link Result#getDocument()} will be null. */ public static class Result { private final boolean parseFailure; private final Document document; public Result(boolean parseFailure, Document document) { this.parseFailure = parseFailure; this.document = document; } public boolean isParseFailure() { return parseFailure; } public Document getDocument() { return document; } } /** * Add the provided document to the cache. */ public static void cache(XmlFileModel key, Document document) { String cacheKey = getKey(key); map.put(cacheKey, new CacheDocument(false, document)); } /** * Cache a parse failure for this document. */ public static void cacheParseFailure(XmlFileModel key) { map.put(getKey(key), new CacheDocument(true, null)); } /** * Retrieve the currently cached value for the given document. */ public static Result get(XmlFileModel key) { String cacheKey = getKey(key); Result result = null; CacheDocument reference = map.get(cacheKey); if (reference == null) return new Result(false, null); if (reference.parseFailure) return new Result(true, null); Document document = reference.getDocument(); if (document == null) LOG.info("Cache miss on XML document: " + cacheKey); return new Result(false, document); } private static String getKey(XmlFileModel key) { return key.getFilePath(); } private static class CacheDocument { private boolean parseFailure; private final SoftReference<Document> document; public CacheDocument(boolean parseFailure, Document document) { this.parseFailure = parseFailure; this.document = new SoftReference<>(document); } public Document getDocument() { return document.get(); } } }