/**
* Copyright (c) 2009--2014 Red Hat, Inc.
*
* This software is licensed to you under the GNU General Public License,
* version 2 (GPLv2). There is NO WARRANTY for this software, express or
* implied, including the implied warranties of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
* along with this software; if not, see
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* Red Hat trademarks are not licensed under GPLv2. No permission is
* granted to use or replicate Red Hat trademarks that are incorporated
* in this software or its documentation.
*/
package com.redhat.rhn.common.util;
import org.apache.log4j.Logger;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* Builds a single OVAL XML file out of individual OVAL files
*
* @version $Rev$
*/
public class OvalFileAggregator {
private static final Logger LOGGER = Logger.getLogger(OvalFileAggregator.class);
private Document aggregate;
private boolean isFinished;
private Map defs;
private Map tests;
private Map objects;
private Map states;
/**
* No-arg constructor
* @throws JDOMException if XML document initialization fails
*/
public OvalFileAggregator() throws JDOMException {
reset();
}
/**
* Adds a OVAL file to the aggregate
* @param f file to add
* @throws JDOMException XML parsing failed
* @throws IOException file IO failed
*/
public void add(File f) throws JDOMException, IOException {
if (f == null) {
return;
}
try {
SAXBuilder builder = new SAXBuilder();
builder.setValidation(false);
add(builder.build(f));
}
catch (JDOMException e) {
LOGGER.error(e.getMessage(), e);
throw e;
}
catch (IOException e) {
LOGGER.error(e.getMessage(), e);
throw e;
}
}
/**
* Adds a parsed OVAL file to the aggregate
* @param doc parsed OVAL file
* @throws JDOMException XMl parsing failed
*/
public void add(Document doc) throws JDOMException {
if (isFinished) {
throw new IllegalStateException();
}
storeDefinitions(doc);
storeTests(doc);
storeObjects(doc);
storeStates(doc);
}
/**
* Finalizes processing and builds the aggregated document
* @param prettyPrint pretty print XML or not
* @return XML in string form
* @throws IOException document output failed
*/
public String finish(boolean prettyPrint) throws IOException {
if (!isFinished && !isEmpty()) {
buildDocument();
isFinished = true;
}
if (isEmpty()) {
return "";
}
XMLOutputter out = new XMLOutputter();
if (prettyPrint) {
out.setFormat(Format.getPrettyFormat());
}
else {
out.setFormat(Format.getCompactFormat());
}
StringWriter buffer = new StringWriter();
out.output(aggregate, buffer);
String retval = buffer.toString();
retval = retval.replaceAll(" xmlns:oval=\"removeme\"", "");
return retval.replaceAll(" xmlns:redhat=\"removeme\"", "");
}
private void buildDocument() {
Element defsElement = new Element("definitions");
attachChildren(defsElement, defs);
Element testsElement = new Element("tests");
attachChildren(testsElement, tests);
Element objectsElement = new Element("objects");
attachChildren(objectsElement, objects);
Element statesElement = new Element("states");
attachChildren(statesElement, states);
List children = aggregate.getRootElement().getChildren();
children.add(defsElement);
children.add(testsElement);
children.add(objectsElement);
children.add(statesElement);
}
private boolean isEmpty() {
return defs.size() == 0 && tests.size() == 0 && states.size() == 0;
}
private void attachChildren(Element parent, Map children) {
for (Iterator iter = children.keySet().iterator(); iter.hasNext();) {
String key = (String) iter.next();
Element child = (Element) children.get(key);
parent.getChildren().add(child);
}
}
private void storeStates(Document doc) {
XPathLite xpl = new XPathLite("states");
storeChildren(xpl, doc, states);
}
private void storeObjects(Document doc) {
XPathLite xpl = new XPathLite("objects");
storeChildren(xpl, doc, objects);
}
private void storeTests(Document doc) {
XPathLite xpl = new XPathLite("tests");
storeChildren(xpl, doc, tests);
}
private void storeDefinitions(Document doc) {
XPathLite xpl = new XPathLite("definitions");
storeChildren(xpl, doc, defs);
}
private void storeChildren(XPathLite xpl, Document doc, Map container) {
for (Iterator iter = xpl.selectChildren(doc).iterator(); iter.hasNext();) {
Element child = (Element) iter.next();
String key = child.getAttributeValue("id");
if (key == null) {
continue;
}
if (container.containsKey(key)) {
continue;
}
container.put(key, child.clone());
}
}
private void reset() {
Namespace schema = Namespace.getNamespace(
"xsi", "http://www.w3.org/2000/10/XMLSchema-instance");
Namespace oval = Namespace.getNamespace("oval", "removeme");
aggregate = new Document();
Element root = new Element("oval_definitions");
root.setAttribute("schemaLocation",
"http://oval.mitre.org/XMLSchema/oval-common-5 " +
"oval-common-schema.xsd " +
"http://oval.mitre.org/XMLSchema/oval-definitions-5 " +
"oval-definitions-schema.xsd " +
"http://oval.mitre.org/XMLSchema/oval-definitions-5#unix " +
"unix-definitions-schema.xsd " +
"http://oval.mitre.org/XMLSchema/oval-definitions-5#redhat " +
"redhat-definitions-schema.xsd", schema);
aggregate.setRootElement(root);
Element generator = new Element("generator");
Element prodName = new Element("product_name", oval);
prodName.setText("Spacewalk");
Element schemaVersion = new Element("schema_version", oval);
schemaVersion.addNamespaceDeclaration(oval);
schemaVersion.setText("5.0");
Element timestamp = new Element("timestamp", oval);
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
StringBuilder date = new StringBuilder();
date.append(cal.get(Calendar.YEAR));
date.append("-");
int month = cal.get(Calendar.MONTH);
if (month < 10) {
date.append("0");
}
date.append(month);
date.append("-");
int day = cal.get(Calendar.DATE);
if (day < 10) {
date.append("0");
}
date.append(day);
date.append("T").append(cal.get(Calendar.HOUR_OF_DAY));
date.append(":").append(cal.get(Calendar.MINUTE));
date.append(":").append(cal.get(Calendar.SECOND));
timestamp.setText(date.toString());
root.getChildren().add(generator);
generator.getChildren().add(prodName);
generator.getChildren().add(schemaVersion);
generator.getChildren().add(timestamp);
defs = new LinkedHashMap();
tests = new LinkedHashMap();
objects = new LinkedHashMap();
states = new LinkedHashMap();
}
}