package org.jboss.windup.rules.apps.xml;
import static org.joox.JOOX.$;
import java.util.Iterator;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jboss.windup.config.AbstractRuleProvider;
import org.jboss.windup.config.GraphRewrite;
import org.jboss.windup.config.loader.RuleLoaderContext;
import org.jboss.windup.config.metadata.MetadataBuilder;
import org.jboss.windup.config.operation.iteration.AbstractIterationOperation;
import org.jboss.windup.config.phase.ClassifyFileTypesPhase;
import org.jboss.windup.config.query.Query;
import org.jboss.windup.graph.service.GraphService;
import org.jboss.windup.reporting.service.ClassificationService;
import org.jboss.windup.rules.apps.xml.model.DoctypeMetaModel;
import org.jboss.windup.rules.apps.xml.model.NamespaceMetaModel;
import org.jboss.windup.rules.apps.xml.model.XmlFileModel;
import org.jboss.windup.rules.apps.xml.service.DoctypeMetaService;
import org.jboss.windup.rules.apps.xml.service.NamespaceService;
import org.jboss.windup.rules.apps.xml.service.XmlFileService;
import org.jboss.windup.rules.files.FileMapping;
import org.jboss.windup.util.xml.LocationAwareContentHandler;
import org.jboss.windup.util.xml.LocationAwareContentHandler.Doctype;
import org.jboss.windup.util.xml.XmlUtil;
import org.ocpsoft.rewrite.config.Configuration;
import org.ocpsoft.rewrite.config.ConfigurationBuilder;
import org.ocpsoft.rewrite.context.EvaluationContext;
import org.w3c.dom.Document;
/**
* Extract some basic metadata from all {@link XmlFileModel}s found in the graph.
*/
public class DiscoverXmlFilesRuleProvider extends AbstractRuleProvider
{
private static final Logger LOG = Logger.getLogger(DiscoverXmlFilesRuleProvider.class.getSimpleName());
public DiscoverXmlFilesRuleProvider()
{
super(MetadataBuilder.forProvider(DiscoverXmlFilesRuleProvider.class)
.setPhase(ClassifyFileTypesPhase.class));
}
@Override
public Configuration getConfiguration(RuleLoaderContext ruleLoaderContext)
{
return ConfigurationBuilder.begin()
.addRule(FileMapping.from(".*\\.xml$").to(XmlFileModel.class))
.addRule(FileMapping.from(".*\\.xmi$").to(XmlFileModel.class))
.addRule(FileMapping.from(".*\\.jsf$").to(XmlFileModel.class))
.addRule(FileMapping.from(".*\\.xhtml$").to(XmlFileModel.class))
.addRule()
.when(Query.fromType(XmlFileModel.class))
.perform(new AbstractIterationOperation<XmlFileModel>()
{
@Override
public void perform(GraphRewrite event, EvaluationContext context, XmlFileModel payload)
{
addXmlMetaInformation(event, context, payload);
}
@Override
public String toString()
{
return "IndexXmlFilesMetadata";
}
});
}
private void addXmlMetaInformation(GraphRewrite event, EvaluationContext context, XmlFileModel file)
{
DoctypeMetaService docTypeService = new DoctypeMetaService(event.getGraphContext());
NamespaceService namespaceService = new NamespaceService(event.getGraphContext());
try
{
Document parsedDocument = file.asDocument();
// pull out doctype data.
Doctype docType = (Doctype) parsedDocument.getUserData(LocationAwareContentHandler.DOCTYPE_KEY_NAME);
// if this is successful, then we know it is a proper XML file.
// set it to the graph as an XML file.
XmlFileModel xmlResourceModel = GraphService.addTypeToModel(event.getGraphContext(), file, XmlFileModel.class);
// get and index by the root tag.
String tagName = $(parsedDocument).tag();
xmlResourceModel.setRootTagName(tagName);
if (docType != null)
{
// create the doctype from
Iterator<DoctypeMetaModel> metas = docTypeService.findByPublicIdAndSystemId(docType.getPublicId(),
docType.getSystemId());
if (metas.hasNext())
{
DoctypeMetaModel meta = metas.next();
meta.addXmlResource(xmlResourceModel);
xmlResourceModel.setDoctype(meta);
}
else
{
DoctypeMetaModel meta = event.getGraphContext().getFramed().addVertex(null, DoctypeMetaModel.class);
meta.addXmlResource(xmlResourceModel);
meta.setBaseURI(docType.getBaseURI());
meta.setName(docType.getName());
meta.setPublicId(docType.getPublicId());
meta.setSystemId(docType.getSystemId());
}
}
Map<String, String> namespaceSchemaLocations = XmlUtil.getSchemaLocations(parsedDocument);
if (namespaceSchemaLocations != null && namespaceSchemaLocations.size() > 0)
{
for (String namespace : namespaceSchemaLocations.keySet())
{
NamespaceMetaModel meta = namespaceService.createNamespaceSchemaLocation(namespace,
namespaceSchemaLocations.get(namespace));
meta.addXmlResource(xmlResourceModel);
}
}
}
catch (Exception e)
{
if (file.asFile().length() == 0)
{
final String message = "Failed to parse XML entity: " + file.getFilePath() + ": the file is empty.";
LOG.log(Level.FINE, message);
file.setParseError(message);
}
else
{
final String message = "Failed to parse XML entity: " + file.getFilePath() + ", due to: " + e.getMessage();
LOG.log(Level.INFO, message);
LOG.log(Level.FINE, message, e);
file.setParseError(message);
}
new ClassificationService(event.getGraphContext())
.attachClassification(event, context, file, XmlFileService.UNPARSEABLE_XML_CLASSIFICATION, XmlFileService.UNPARSEABLE_XML_DESCRIPTION);
}
}
}