package org.jboss.windup.rules.apps.xml.service; import java.io.IOException; import java.io.InputStream; import java.util.logging.Level; import java.util.logging.Logger; import org.jboss.windup.config.GraphRewrite; import org.jboss.windup.graph.GraphContext; import org.jboss.windup.graph.service.GraphService; import org.jboss.windup.reporting.model.ClassificationModel; import org.jboss.windup.reporting.service.ClassificationService; import org.jboss.windup.rules.apps.xml.model.XMLDocumentCache; import org.jboss.windup.rules.apps.xml.model.XmlFileModel; import org.jboss.windup.util.exception.WindupException; import org.jboss.windup.util.xml.LocationAwareXmlReader; import org.ocpsoft.rewrite.context.EvaluationContext; import org.w3c.dom.Document; import org.xml.sax.SAXException; /** * Manages creating, querying, and deleting XmlFileModels. * * @author <a href="mailto:jesse.sightler@gmail.com">Jesse Sightler</a> * @author Ondrej Zizka */ public class XmlFileService extends GraphService<XmlFileModel> { private static final Logger LOG = Logger.getLogger(XmlFileService.class.getSimpleName()); public final static String UNPARSEABLE_XML_CLASSIFICATION = "Unparsable XML File"; public final static String UNPARSEABLE_XML_DESCRIPTION = "This file could not be parsed"; public XmlFileService(GraphContext ctx) { super(ctx, XmlFileModel.class); } /** * Loads and parses the provided XML file. This will quietly fail (not throwing an {@link Exception}) and return * null if it is unable to parse the provided {@link XmlFileModel}. A {@link ClassificationModel} will be created to * indicate that this file failed to parse. * * @return Returns either the parsed {@link Document} or null if the {@link Document} could not be parsed */ public Document loadDocumentQuiet(GraphRewrite event, EvaluationContext context, XmlFileModel model) { try { return loadDocument(event, context, model); } catch(Exception ex) { return null; } } /** * Loads and parses the provided XML file. This will quietly fail (not throwing an {@link Exception}) and return * null if it is unable to parse the provided {@link XmlFileModel}. A {@link ClassificationModel} will be created to * indicate that this file failed to parse. * * @return Returns either the parsed {@link Document} or null if the {@link Document} could not be parsed */ public Document loadDocument(GraphRewrite event, EvaluationContext context, XmlFileModel model) throws WindupException { if (model.asFile().length() == 0) { final String msg = "Failed to parse, XML file is empty: " + model.getFilePath(); LOG.log(Level.WARNING, msg); model.setParseError(msg); throw new WindupException(msg); } ClassificationService classificationService = new ClassificationService(getGraphContext()); XMLDocumentCache.Result cacheResult = XMLDocumentCache.get(model); if (cacheResult.isParseFailure()) { final String msg = "Not loading XML file '" + model.getFilePath() + "' due to previous parse failure: " + model.getParseError(); LOG.log(Level.FINE, msg); //model.setParseError(msg); throw new WindupException(msg); } Document document = cacheResult.getDocument(); if (document != null) return document; // Not yet cached - load, store in cache and return. try (InputStream is = model.asInputStream()) { document = LocationAwareXmlReader.readXML(is); XMLDocumentCache.cache(model, document); } catch (SAXException | IOException e) { XMLDocumentCache.cacheParseFailure(model); document = null; final String message = "Failed to parse XML file: " + model.getFilePath() + ", due to: " + e.getMessage(); LOG.log(Level.WARNING, message); classificationService.attachClassification(event, context, model, UNPARSEABLE_XML_CLASSIFICATION, UNPARSEABLE_XML_DESCRIPTION); model.setParseError(message); throw new WindupException(message, e); } return document; } }