/*
Copyright (C) 2003 EBI, GRL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ensembl.mart.lib.config;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.DigestOutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Logger;
import org.jdom.Attribute;
import org.jdom.DocType;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.jdom.output.XMLOutputter;
import org.xml.sax.InputSource;
/**
* Utility class containing all necessary XML parsing logic for converting
* between XML and Object. Uses JDOM as its XML parsing engine.
*
* @author <a href="mailto:dlondon@ebi.ac.uk">Darin London</a>
* @author <a href="mailto:craig@ebi.ac.uk">Craig Melsopp</a>
*/
public class DatasetConfigXMLUtils {
private Logger logger = Logger.getLogger(DatasetConfigXMLUtils.class.getName());
//this is the only digest algorithm we support
public static String DEFAULTDIGESTALGORITHM = "MD5";
// element names
private final String DATASETCONFIG = "DatasetConfig";
private final String STARBASE = "MainTable";
private final String PRIMARYKEY = "Key";
private final String BATCHSIZE = "BatchSize";
private final String IMPORTABLE = "Importable";
private final String EXPORTABLE = "Exportable";
private final String FILTERPAGE = "FilterPage";
private final String FILTERGROUP = "FilterGroup";
private final String DSFILTERGROUP = "DSFilterGroup";
private final String FILTERCOLLECTION = "FilterCollection";
private final String FILTERDESCRIPTION = "FilterDescription";
private final String ATTRIBUTEPAGE = "AttributePage";
private final String ATTRIBUTEGROUP = "AttributeGroup";
private final String ATTRIBUTECOLLECTION = "AttributeCollection";
private final String ATTRIBUTEDESCRIPTION = "AttributeDescription";
private final String ATTRIBUTELIST = "AttributeList";
private final String SPECIFICOPTIONCONTENT = "SpecificOptionContent";
private final String SPECIFICFILTERCONTENT = "SpecificFilterContent";
private final String SPECIFICATTRIBUTECONTENT = "SpecificAttributeContent";
private final String DYNAMICDATASET = "DynamicDataset";
private final String DSATTRIBUTEGROUP = "DSAttributeGroup";
private final String OPTION = "Option";
private final String PUSHACTION = "PushAction";
// attribute names needed by code
private final String INTERNALNAME = "internalName";
private final String OPTPARAM = "optional_parameters";
private final String SOFTWAREVERSION = "softwareVersion";
private final String NOCOUNT = "noCount";
private final String PRIMARYKEYRESTRICTION = "primaryKeyRestriction";
private final String TEMPLATE = "template";
private final String VISIBLEFILTERPAGEPARAM = "visibleFilterPage";
private final String DEFAULTDATASET = "defaultDataset";
private final String HIDDEN = "hidden";
private boolean loadFully = false;
protected boolean includeHiddenMembers = false;
public DatasetConfigXMLUtils(boolean includeHiddenMembers) {
this.includeHiddenMembers = includeHiddenMembers;
}
/**
* Set the load behavior of the getDatasetConfigXXX methods. If set to true, all DatasetConfig objects are
* fully loaded, if false, this is deferred to the lazyLoad system. This is primarily for the DatasetConfigCache
* object.
* @param loadFully -- boolean, if true instructs all subsequent getDatasetConfigXXX calls to fully load the DatasetConfig
* object before loading it, if false defers this to the lazyLoad system
*/
protected void setFullyLoadMode(boolean loadFully) {
this.loadFully = loadFully;
}
public DatasetConfig getDatasetConfigForByteArray(byte[] b) throws ConfigurationException {
return getDatasetConfigForByteArray(b, null);
}
/**
* Returns a DatasetConfig from an XML stored as a byte[], allowing the system to specify whether to
* load all Elements, or defer this to the lazyLoad system. Also allows system
* to supply a md5sum digest byte[] array to store into the resulting DatasetConfig.
*
* @param b - byte[] holding XML
* @param digest -- byte[] containing the digest
* @return DatasetConfig for xml in byte[]
* @throws ConfigurationException
*/
public DatasetConfig getDatasetConfigForByteArray(byte[] b, byte[] digest) throws ConfigurationException {
ByteArrayInputStream bin = new ByteArrayInputStream(b);
return getDatasetConfigForXMLStream(bin, digest);
}
public DatasetConfig getDatasetConfigForXMLStream(InputStream xmlinput) throws ConfigurationException {
return getDatasetConfigForXMLStream(xmlinput, null);
}
/**
* Takes an InputStream containing XML, and creates a DatasetConfig object.
* If a MessageDigest is supplied, this will be added to the DatasetConfig object
* before returning it.
*
* @param xmlinput -- InputStream containing DatasetConfig.dtd compliant XML
* @param digest -- byte[] containing the digest
* @return DatasetConfig
* @throws ConfigurationException for all underlying Exceptions
* @see java.security.MessageDigest
*/
public DatasetConfig getDatasetConfigForXMLStream(InputStream xmlinput, byte[] digest) throws ConfigurationException {
return getDatasetConfigForDocument(getDocumentForXMLStream(xmlinput), digest);
}
/**
* Takes an InputStream containing DatasetConfig.dtd compliant XML, and creates a JDOM Document.
* @param xmlinput -- InputStream containin DatasetConfig.dtd compliant XML
* @return org.jdom.Document
* @throws ConfigurationException for all underlying Exceptions
*/
public Document getDocumentForXMLStream(InputStream xmlinput) throws ConfigurationException {
try {
SAXBuilder builder = new SAXBuilder();
// set the EntityResolver to a mart DB aware version, allowing it to get the DTD from the Classpath.
builder.setEntityResolver(new ClasspathDTDEntityResolver());
builder.setValidation(false);
InputSource is = new InputSource(xmlinput);
Document doc = builder.build(is);
return doc;
} catch (Exception e) {
throw new ConfigurationException(e);
}
}
/**
* Takes a org.jdom.Document Object representing a DatasetConfig.dtd compliant
* XML document, and returns a DatasetConfig object.
* @param doc -- Document representing a DatasetConfig.dtd compliant XML document
* @return DatasetConfig object
* @throws ConfigurationException for non compliant Objects, and all underlying Exceptions.
*/
public DatasetConfig getDatasetConfigForDocument(Document doc) throws ConfigurationException {
return getDatasetConfigForDocument(doc, null);
}
/**
* Takes a org.jdom.Document Object representing a DatasetConfig.dtd compliant
* XML document, and returns a DatasetConfig object. If a MD5SUM Message Digest is
* supplied, this is added to the DatasetConfig.
* @param doc -- Document representing a DatasetConfig.dtd compliant XML document
* @param digest -- a digest computed with the given digestAlgorithm
* @return DatasetConfig object
* @throws ConfigurationException for non compliant Objects, and all underlying Exceptions.
*/
public DatasetConfig getDatasetConfigForDocument(Document doc, byte[] digest) throws ConfigurationException {
Element thisElement = doc.getRootElement();
DatasetConfig d = new DatasetConfig();
loadAttributesFromElement(thisElement, d);
if (loadFully)
loadDatasetConfigWithDocument(d, doc);
if (digest != null)
d.setMessageDigest(digest);
return d;
}
private void loadAttributesFromElement(Element thisElement, BaseConfigurationObject obj) {
List attributes = thisElement.getAttributes();
for (int i = 0, n = attributes.size(); i < n; i++) {
Attribute att = (Attribute) attributes.get(i);
String name = att.getName();
obj.setAttribute(name, thisElement.getAttributeValue(name));
}
}
/**
* Takes a reference to a DatasetConfig, and a JDOM Document, and parses the JDOM document to add all of the information
* from the XML for a particular DatasetConfig object into the existing DatasetConfig reference passed into the method.
* @param dsv -- DatasetConfig reference to be updated
* @param doc -- Document containing DatasetConfig.dtd compliant XML for dsv
* @throws ConfigurationException when the internalName returned by the JDOM Document does not match
* that of the dsv reference, and for any other underlying Exception
*/
public void loadDatasetConfigWithDocument(DatasetConfig dsv, Document doc) throws ConfigurationException {
Element thisElement = doc.getRootElement();
/*
String intName = thisElement.getAttributeValue(INTERNALNAME, "");
String optParam = thisElement.getAttributeValue(OPTPARAM, "");
String softwareVersion = thisElement.getAttributeValue(SOFTWAREVERSION, "");
String noCount = thisElement.getAttributeValue(NOCOUNT, "");
String primaryKeyRestriction = thisElement.getAttributeValue(PRIMARYKEYRESTRICTION, "");
String template = thisElement.getAttributeValue(TEMPLATE, "");
String defParam = thisElement.getAttributeValue(DEFAULTDATASET, "");
String visibleFilterPageParam = thisElement.getAttributeValue(VISIBLEFILTERPAGEPARAM, "");
String displayName = thisElement.getAttributeValue("displayName","");
String description = thisElement.getAttributeValue("description","");
String version = thisElement.getAttributeValue("version","");
String entryLabel = thisElement.getAttributeValue("entryLabel","");
if (displayName.length() > 0)
dsv.setDisplayName(displayName);
if (description.length() > 0)
dsv.setDescription(description);
if (version.length() > 0)
dsv.setVersion(version);
if (visibleFilterPageParam.length() > 0)
dsv.setVisibleFilterPage(visibleFilterPageParam);
if (optParam.length() > 0)
dsv.setOptionalParameter(optParam);
if (entryLabel.length() > 0)
dsv.setEntryLabel(entryLabel);
if (softwareVersion.length() > 0)
dsv.setSoftwareVersion(softwareVersion);
if (noCount.length() > 0)
dsv.setNoCount(noCount);
if (primaryKeyRestriction.length() > 0)
dsv.setPrimaryKeyRestriction(primaryKeyRestriction);
if (template.length() > 0)
dsv.setTemplate(template);
if (defParam.length() > 0)
dsv.setDefaultDataset(defParam);
*/
// a DatasetConfig object must have been constructed with an internalName
// test that the internalNames match , throw an exception if they are not
// internalName of document doesn't have to match now
//if (!intName.equals(dsv.getInternalName()))
// throw new ConfigurationException("Document internalName does not match input dsv reference internalName, they may not represent the same data\n");
loadAttributesFromElement(thisElement, dsv);
for (Iterator iter = thisElement.getChildren(OPTION).iterator(); iter.hasNext();) {
Element option = (Element) iter.next();
if (!(Boolean.valueOf(option.getAttributeValue(HIDDEN)).booleanValue()))
dsv.addOption(getOption(option));
}
for (Iterator iter = thisElement.getDescendants(new MartElementFilter(includeHiddenMembers, STARBASE));
iter.hasNext();
) {
Element element = (Element) iter.next();
dsv.addMainTable(element.getTextNormalize());
}
for (Iterator iter = thisElement.getDescendants(new MartElementFilter(includeHiddenMembers, PRIMARYKEY));
iter.hasNext();
) {
Element element = (Element) iter.next();
dsv.addPrimaryKey(element.getTextNormalize());
}
for (Iterator iter = thisElement.getDescendants(new MartElementFilter(includeHiddenMembers, BATCHSIZE));
iter.hasNext();
) {
Element element = (Element) iter.next();
dsv.addBatchSize(element.getTextNormalize());
}
for (Iterator iter = thisElement.getDescendants(new MartElementFilter(includeHiddenMembers, DYNAMICDATASET));
iter.hasNext();
) {
Element element = (Element) iter.next();
dsv.addDynamicDataset(getDynamicDataset(element));
}
for (Iterator iter = thisElement.getDescendants(new MartElementFilter(includeHiddenMembers, IMPORTABLE));
iter.hasNext();
) {
Element element = (Element) iter.next();
dsv.addImportable(getImportable(element));
}
for (Iterator iter = thisElement.getDescendants(new MartElementFilter(includeHiddenMembers, EXPORTABLE));
iter.hasNext();
) {
Element element = (Element) iter.next();
dsv.addExportable(getExportable(element));
}
for (Iterator iter = thisElement.getDescendants(new MartElementFilter(includeHiddenMembers, FILTERPAGE));
iter.hasNext();
) {
Element element = (Element) iter.next();
dsv.addFilterPage(getFilterPage(element));
}
for (Iterator iter = thisElement.getDescendants(new MartElementFilter(includeHiddenMembers, ATTRIBUTEPAGE));
iter.hasNext();
) {
Element element = (Element) iter.next();
dsv.addAttributePage(getAttributePage(element));
}
// we need to manually set the "parent" references on these options
// so they are availbe for future use.
List fds = dsv.getAllFilterDescriptions();
for (Iterator iter = fds.iterator(); iter.hasNext();) {
FilterDescription fd = (FilterDescription) iter.next();
fd.setParentsForAllPushOptionOptions(dsv);
}
}
private Importable getImportable(Element thisElement) throws ConfigurationException {
Importable im = new Importable();
loadAttributesFromElement(thisElement, im);
return im;
}
private Exportable getExportable(Element thisElement) throws ConfigurationException {
Exportable ex = new Exportable();
loadAttributesFromElement(thisElement, ex);
return ex;
}
private FilterPage getFilterPage(Element thisElement) throws ConfigurationException {
FilterPage fp = new FilterPage();
loadAttributesFromElement(thisElement, fp);
for (Iterator iter = thisElement.getDescendants(new MartFilterGroupFilter(includeHiddenMembers)); iter.hasNext();) {
Element element = (Element) iter.next();
if (element.getName().equals(FILTERGROUP))
fp.addFilterGroup(getFilterGroup(element));
}
return fp;
}
private FilterGroup getFilterGroup(Element thisElement) throws ConfigurationException {
FilterGroup fg = new FilterGroup();
loadAttributesFromElement(thisElement, fg);
for (Iterator iter = thisElement.getDescendants(new MartElementFilter(includeHiddenMembers, FILTERCOLLECTION));
iter.hasNext();
) {
Element element = (Element) iter.next();
fg.addFilterCollection(getFilterCollection(element));
}
return fg;
}
private FilterCollection getFilterCollection(Element thisElement) throws ConfigurationException {
FilterCollection fc = new FilterCollection();
loadAttributesFromElement(thisElement, fc);
for (Iterator iter = thisElement.getDescendants(new MartFilterDescriptionFilter(includeHiddenMembers));
iter.hasNext();
) {
Element element = (Element) iter.next();
fc.addFilterDescription(getFilterDescription(element));
}
return fc;
}
private Option getOption(Element thisElement) throws ConfigurationException {
Option o = new Option();
loadAttributesFromElement(thisElement, o);
for (Iterator iter = thisElement.getChildren(OPTION).iterator(); iter.hasNext();) {
Element suboption = (Element) iter.next();
if (includeHiddenMembers){
Option o2 = getOption(suboption);
o2.setParent(o);
o.addOption(o2);
}
else if (!(Boolean.valueOf(suboption.getAttributeValue(HIDDEN)).booleanValue())) {
Option o2 = getOption(suboption);
o2.setParent(o);
o.addOption(o2);
}
}
for (Iterator iter = thisElement.getDescendants(new MartElementFilter(includeHiddenMembers, SPECIFICOPTIONCONTENT));
iter.hasNext();
) {
Element element = (Element) iter.next();
o.addSpecificOptionContent(getSpecificOptionContent(element));
}
for (Iterator iter = thisElement.getChildren(PUSHACTION).iterator(); iter.hasNext();) {
o.addPushAction(getPushOptions((Element) iter.next()));
}
return o;
}
private PushAction getPushOptions(Element thisElement) throws ConfigurationException {
PushAction pa = new PushAction();
loadAttributesFromElement(thisElement, pa);
for (Iterator iter = thisElement.getChildren(OPTION).iterator(); iter.hasNext();) {
Element option = (Element) iter.next();
if (includeHiddenMembers){
pa.addOption(getOption(option));
}
else if (!(Boolean.valueOf(option.getAttributeValue(HIDDEN)).booleanValue()))
pa.addOption(getOption(option));
}
return pa;
}
private FilterDescription getFilterDescription(Element thisElement) throws ConfigurationException {
FilterDescription f = new FilterDescription();
loadAttributesFromElement(thisElement, f);
for (Iterator iter = thisElement.getDescendants(new MartElementFilter(includeHiddenMembers, SPECIFICFILTERCONTENT));
iter.hasNext();
) {
Element element = (Element) iter.next();
f.addSpecificFilterContent(getSpecificFilterContent(element));
}
for (Iterator iter = thisElement.getChildren(OPTION).iterator(); iter.hasNext();) {
Element option = (Element) iter.next();
if (includeHiddenMembers){
Option o = getOption(option);
o.setParent(f);
f.addOption(o);
}
else if (!(Boolean.valueOf(option.getAttributeValue(HIDDEN)).booleanValue())) {
Option o = getOption(option);
o.setParent(f);
f.addOption(o);
}
}
return f;
}
private AttributePage getAttributePage(Element thisElement) throws ConfigurationException {
AttributePage ap = new AttributePage();
loadAttributesFromElement(thisElement, ap);
for (Iterator iter = thisElement.getDescendants(new MartAttributeGroupFilter()); iter.hasNext();) {
Element element = (Element) iter.next();
if (element.getName().equals(ATTRIBUTEGROUP))
ap.addAttributeGroup(getAttributeGroup(element));
}
return ap;
}
private AttributeGroup getAttributeGroup(Element thisElement) throws ConfigurationException {
AttributeGroup ag = new AttributeGroup();
loadAttributesFromElement(thisElement, ag);
for (Iterator iter = thisElement.getDescendants(new MartElementFilter(includeHiddenMembers, ATTRIBUTECOLLECTION));
iter.hasNext();
) {
Element element = (Element) iter.next();
ag.addAttributeCollection(getAttributeCollection(element));
}
return ag;
}
private AttributeCollection getAttributeCollection(Element thisElement) throws ConfigurationException {
AttributeCollection ac = new AttributeCollection();
loadAttributesFromElement(thisElement, ac);
for (Iterator iter = thisElement.getDescendants(new MartElementFilter(includeHiddenMembers, ATTRIBUTEDESCRIPTION));
iter.hasNext();
) {
Element element = (Element) iter.next();
ac.addAttributeDescription(getAttributeDescription(element));
}
for (Iterator iter = thisElement.getDescendants(new MartElementFilter(includeHiddenMembers, ATTRIBUTELIST));
iter.hasNext();
) {
Element element = (Element) iter.next();
ac.addAttributeList(getAttributeList(element));
}
return ac;
}
private AttributeList getAttributeList(Element thisElement) throws ConfigurationException {
AttributeList a = new AttributeList();
loadAttributesFromElement(thisElement, a);
return a;
}
private AttributeDescription getAttributeDescription(Element thisElement) throws ConfigurationException {
AttributeDescription a = new AttributeDescription();
loadAttributesFromElement(thisElement, a);
for (Iterator iter = thisElement.getDescendants(new MartElementFilter(includeHiddenMembers, SPECIFICATTRIBUTECONTENT));
iter.hasNext();
) {
Element element = (Element) iter.next();
a.addSpecificAttributeContent(getSpecificAttributeContent(element));
}
return a;
}
private SpecificAttributeContent getSpecificAttributeContent(Element thisElement) throws ConfigurationException {
SpecificAttributeContent f = new SpecificAttributeContent();
loadAttributesFromElement(thisElement, f);
return f;
}
private SpecificFilterContent getSpecificFilterContent(Element thisElement) throws ConfigurationException {
SpecificFilterContent f = new SpecificFilterContent();
loadAttributesFromElement(thisElement, f);
for (Iterator iter = thisElement.getChildren(OPTION).iterator(); iter.hasNext();) {
Element option = (Element) iter.next();
if (includeHiddenMembers){
Option o = getOption(option);
//o.setParent(f);
o.setParent(null);
f.addOption(o);
}
else if (!(Boolean.valueOf(option.getAttributeValue(HIDDEN)).booleanValue())) {
Option o = getOption(option);
//o.setParent(f);
o.setParent(null);
f.addOption(o);
}
}
return f;
}
private SpecificOptionContent getSpecificOptionContent(Element thisElement) throws ConfigurationException {
SpecificOptionContent f = new SpecificOptionContent();
loadAttributesFromElement(thisElement, f);
for (Iterator iter = thisElement.getChildren(OPTION).iterator(); iter.hasNext();) {
Element option = (Element) iter.next();
if (includeHiddenMembers){
Option o = getOption(option);
//o.setParent(f);
o.setParent(null);
f.addOption(o);
}
else if (!(Boolean.valueOf(option.getAttributeValue(HIDDEN)).booleanValue())) {
Option o = getOption(option);
//o.setParent(f);
o.setParent(null);
f.addOption(o);
}
}
return f;
}
private DynamicDataset getDynamicDataset(Element thisElement) throws ConfigurationException {
DynamicDataset a = new DynamicDataset();
loadAttributesFromElement(thisElement, a);
return a;
}
/**
* Writes a DatasetConfig object as XML to the given File. Handles opening and closing of the OutputStream.
* @param dsv -- DatasetConfig object
* @param file -- File to write XML
* @throws ConfigurationException for underlying Exceptions
*/
public void writeDatasetConfigToFile(DatasetConfig dsv, File file) throws ConfigurationException {
writeDocumentToFile(getDocumentForDatasetConfig(dsv), file);
}
/**
* Writes a DatasetConfig object as XML to the given OutputStream. Does not close the OutputStream after writing.
* If you wish to write a Document to a File, use DatasetConfigToFile instead, as it handles opening and closing the OutputStream.
* @param dsv -- DatasetConfig object to write as XML
* @param out -- OutputStream to write, not closed after writing
* @throws ConfigurationException for underlying Exceptions
*/
public void writeDatasetConfigToOutputStream(DatasetConfig dsv, OutputStream out) throws ConfigurationException {
writeDocumentToOutputStream(getDocumentForDatasetConfig(dsv), out);
}
/**
* Writes a JDOM Document as XML to a given File. Handles opening and closing of the OutputStream.
* @param doc -- Document representing a DatasetConfig.dtd compliant XML document
* @param file -- File to write.
* @throws ConfigurationException for underlying Exceptions.
*/
public void writeDocumentToFile(Document doc, File file) throws ConfigurationException {
try {
FileOutputStream out = new FileOutputStream(file);
writeDocumentToOutputStream(doc, out);
out.close();
} catch (FileNotFoundException e) {
throw new ConfigurationException(
"Caught FileNotFoundException writing Document to File provided " + e.getMessage(),
e);
} catch (ConfigurationException e) {
throw e;
} catch (IOException e) {
throw new ConfigurationException("Caught IOException creating FileOutputStream " + e.getMessage(), e);
}
}
/**
* Takes a JDOM Document and writes it as DatasetConfig.dtd compliant XML to a given OutputStream.
* Does NOT close the OutputStream after writing. If you wish to write a Document to a File,
* use DocumentToFile instead, as it handles opening and closing the OutputStream.
* @param doc -- Document representing a DatasetConfig.dtd compliant XML document
* @param out -- OutputStream to write to, not closed after writing
* @throws ConfigurationException for underlying IOException
*/
public void writeDocumentToOutputStream(Document doc, OutputStream out) throws ConfigurationException {
XMLOutputter xout = new XMLOutputter(org.jdom.output.Format.getRawFormat());
try {
xout.output(doc, out);
} catch (IOException e) {
throw new ConfigurationException("Caught IOException writing XML to OutputStream " + e.getMessage(), e);
}
}
private void loadElementAttributesFromObject(BaseConfigurationObject obj, Element thisElement) {
String[] titles = obj.getXmlAttributeTitles();
//String[] titles = (String[])obj.attributes.keySet().toArray(new String[0]);
//sort the attribute titles before writing them out, so that MD5SUM is supported
Arrays.sort(titles);
for (int i = 0, n = titles.length; i < n; i++) {
String key = titles[i];
if (validString(obj.getAttribute(key)))
thisElement.setAttribute(key, obj.getAttribute(key));
}
}
/**
* Takes a DatasetConfig object, and returns a JDOM Document representing the
* XML for this Object. Does not store DataSource or Digest information
* @param dsconfig -- DatasetConfig object to be converted into a JDOM Document
* @return Document object
*/
public Document getDocumentForDatasetConfig(DatasetConfig dsconfig) {
Element root = new Element(DATASETCONFIG);
loadElementAttributesFromObject(dsconfig, root);
List ads = dsconfig.getDynamicDatasets();
for (Iterator iter = ads.iterator(); iter.hasNext();)
root.addContent(getDynamicDatasetElement((DynamicDataset) iter.next()));
Option[] os = dsconfig.getOptions();
for (int i = 0, n = os.length; i < n; i++)
root.addContent(getOptionElement(os[i]));
String[] starbases = dsconfig.getStarBases();
for (int i = 0, n = starbases.length; i < n; i++)
root.addContent(getStarBaseElement(starbases[i]));
String[] pkeys = dsconfig.getPrimaryKeys();
for (int i = 0, n = pkeys.length; i < n; i++)
root.addContent(getPrimaryKeyElement(pkeys[i]));
String[] batchSizes = dsconfig.getBatchSizes();
for (int i = 0, n = batchSizes.length; i < n; i++)
root.addContent(getBatchSizeElement(batchSizes[i]));
Importable[] imps = dsconfig.getImportables();
for (int i = 0, n = imps.length; i < n; i++)
root.addContent(getImportableElement(imps[i]));
Exportable[] exps = dsconfig.getExportables();
for (int i = 0, n = exps.length; i < n; i++)
root.addContent(getExportableElement(exps[i]));
FilterPage[] fpages = dsconfig.getFilterPages();
for (int i = 0, n = fpages.length; i < n; i++)
root.addContent(getFilterPageElement(fpages[i]));
AttributePage[] apages = dsconfig.getAttributePages();
for (int i = 0, n = apages.length; i < n; i++)
root.addContent(getAttributePageElement(apages[i]));
Document thisDoc = new Document(root);
thisDoc.setDocType(new DocType(DATASETCONFIG));
return thisDoc;
}
private Element getAttributePageElement(AttributePage apage) {
Element page = new Element(ATTRIBUTEPAGE);
loadElementAttributesFromObject(apage, page);
List groups = apage.getAttributeGroups();
for (Iterator iter = groups.iterator(); iter.hasNext();) {
Object group = iter.next();
if (group instanceof AttributeGroup)
page.addContent(getAttributeGroupElement((AttributeGroup) group));
}
return page;
}
private Element getAttributeGroupElement(AttributeGroup group) {
Element ag = new Element(ATTRIBUTEGROUP);
loadElementAttributesFromObject(group, ag);
AttributeCollection[] acs = group.getAttributeCollections();
for (int i = 0, n = acs.length; i < n; i++)
ag.addContent(getAttributeCollectionElement(acs[i]));
return ag;
}
private Element getAttributeCollectionElement(AttributeCollection collection) {
Element ac = new Element(ATTRIBUTECOLLECTION);
loadElementAttributesFromObject(collection, ac);
List ads = collection.getAttributeDescriptions();
for (Iterator iter = ads.iterator(); iter.hasNext();)
ac.addContent(getAttributeDescriptionElement((AttributeDescription) iter.next()));
ads = collection.getAttributeLists();
for (Iterator iter = ads.iterator(); iter.hasNext();)
ac.addContent(getAttributeListElement((AttributeList) iter.next()));
return ac;
}
private Element getAttributeListElement(AttributeList attribute) {
Element att = new Element(ATTRIBUTELIST);
loadElementAttributesFromObject(attribute, att);
return att;
}
private Element getAttributeDescriptionElement(AttributeDescription attribute) {
Element att = new Element(ATTRIBUTEDESCRIPTION);
loadElementAttributesFromObject(attribute, att);
for (Iterator i = attribute.getSpecificAttributeContents().iterator(); i.hasNext(); )
att.addContent(getSpecificAttributeContentElement((SpecificAttributeContent)i.next()));
return att;
}
private Element getSpecificAttributeContentElement(SpecificAttributeContent dynAttribute) {
Element datt = new Element(SPECIFICATTRIBUTECONTENT);
loadElementAttributesFromObject(dynAttribute, datt);
return datt;
}
private Element getSpecificFilterContentElement(SpecificFilterContent dynAttribute) {
Element datt = new Element(SPECIFICFILTERCONTENT);
loadElementAttributesFromObject(dynAttribute, datt);
Option[] subops = dynAttribute.getOptions();
for (int i = 0, n = subops.length; i < n; i++){
datt.addContent(getOptionElement(subops[i]));
}
return datt;
}
private Element getSpecificOptionContentElement(SpecificOptionContent dynAttribute) {
Element datt = new Element(SPECIFICOPTIONCONTENT);
loadElementAttributesFromObject(dynAttribute, datt);
Option[] subops = dynAttribute.getOptions();
for (int i = 0, n = subops.length; i < n; i++){
datt.addContent(getOptionElement(subops[i]));
}
return datt;
}
private Element getDynamicDatasetElement(DynamicDataset dynAttribute) {
Element datt = new Element(DYNAMICDATASET);
loadElementAttributesFromObject(dynAttribute, datt);
return datt;
}
private Element getFilterPageElement(FilterPage fpage) {
Element page = new Element(FILTERPAGE);
loadElementAttributesFromObject(fpage, page);
List groups = fpage.getFilterGroups();
for (Iterator iter = groups.iterator(); iter.hasNext();) {
Object group = iter.next();
if (group instanceof FilterGroup)
page.addContent(getFilterGroupElement((FilterGroup) group));
}
return page;
}
/**
* @param group
* @return
*/
private Element getFilterGroupElement(FilterGroup group) {
Element fg = new Element(FILTERGROUP);
loadElementAttributesFromObject(group, fg);
FilterCollection[] acs = group.getFilterCollections();
for (int i = 0, n = acs.length; i < n; i++)
fg.addContent(getFilterCollectionElement(acs[i]));
return fg;
}
private Element getFilterCollectionElement(FilterCollection collection) {
Element fc = new Element(FILTERCOLLECTION);
loadElementAttributesFromObject(collection, fc);
List ads = collection.getFilterDescriptions();
//currently there are only FilterDescription objects, may be DSFilterDescription in the future
for (Iterator iter = ads.iterator(); iter.hasNext();)
fc.addContent(getFilterDescriptionElement((FilterDescription) iter.next()));
return fc;
}
private Element getPrimaryKeyElement(String primaryKeyString) {
Element pkey = new Element(PRIMARYKEY);
pkey.setText(primaryKeyString);
return pkey;
}
private Element getBatchSizeElement(String batchSizeString) {
Element bsize = new Element(BATCHSIZE);
bsize.setText(batchSizeString);
return bsize;
}
private Element getImportableElement(Importable smodule) {
Element module = new Element(IMPORTABLE);
loadElementAttributesFromObject(smodule, module);
return module;
}
private Element getExportableElement(Exportable smodule) {
Element module = new Element(EXPORTABLE);
loadElementAttributesFromObject(smodule, module);
return module;
}
private Element getStarBaseElement(String starbaseString) {
Element sbase = new Element(STARBASE);
sbase.setText(starbaseString);
return sbase;
}
private Element getOptionElement(Option o) {
Element option = new Element(OPTION);
loadElementAttributesFromObject(o, option);
Option[] subops = o.getOptions();
for (int i = 0, n = subops.length; i < n; i++)
option.addContent(getOptionElement(subops[i]));
PushAction[] pushops = o.getPushActions();
for (int i = 0, n = pushops.length; i < n; i++)
option.addContent(getPushActionElement(pushops[i]));
for (Iterator i = o.getSpecificOptionContents().iterator(); i.hasNext(); )
option.addContent(getSpecificOptionContentElement((SpecificOptionContent)i.next()));
return option;
}
private Element getPushActionElement(PushAction pa) {
Element pushAction = new Element(PUSHACTION);
loadElementAttributesFromObject(pa, pushAction);
Option[] os = pa.getOptions();
for (int i = 0, n = os.length; i < n; i++)
pushAction.addContent(getOptionElement(os[i]));
return pushAction;
}
private Element getFilterDescriptionElement(FilterDescription filter) {
Element fdesc = new Element(FILTERDESCRIPTION);
loadElementAttributesFromObject(filter, fdesc);
for (Iterator i = filter.getSpecificFilterContents().iterator(); i.hasNext(); )
fdesc.addContent(getSpecificFilterContentElement((SpecificFilterContent)i.next()));
Option[] subops = filter.getOptions();
for (int i = 0, n = subops.length; i < n; i++)
fdesc.addContent(getOptionElement(subops[i]));
return fdesc;
}
private boolean validString(String test) {
return (test != null && test.length() > 0);
}
/**
* Given a Document object, converts the given document to an DatasetConfigXMLUtils.DEFAULTDIGESTALGORITHM digest using the
* JDOM XMLOutputter writing to a java.security.DigestOutputStream. This is the default method for calculating the MessageDigest
* of a DatasetConfig Object used in various places in the MartJ system.
* @param doc -- Document object representing a DatasetConfig.dtd compliant XML document.
* @return byte[] digest algorithm
* @throws ConfigurationException for NoSuchAlgorithmException, and IOExceptions.
* @see java.security.DigestOutputStream
*/
public byte[] getMessageDigestForDocument(Document doc) throws ConfigurationException {
try {
MessageDigest mdigest = MessageDigest.getInstance(DEFAULTDIGESTALGORITHM);
ByteArrayOutputStream bout = new ByteArrayOutputStream();
DigestOutputStream dout = new DigestOutputStream(bout, mdigest);
XMLOutputter xout = new XMLOutputter(org.jdom.output.Format.getRawFormat());
xout.output(doc, dout);
byte[] digest = mdigest.digest();
bout.close();
dout.close();
System.out.println("DIGEST FOR DOC " + doc.toString() + " IS " + digest.toString());
return digest;
} catch (NoSuchAlgorithmException e) {
throw new ConfigurationException(
"Digest Algorithm " + DEFAULTDIGESTALGORITHM + " does not exist, possibly a problem with the Java Installation\n",
e);
} catch (IOException e) {
throw new ConfigurationException("Caught IOException converting Docuement to Digest\n", e);
}
}
/**
* Returns a MessageDigest digest for a DatasetConfig by first creating a JDOM Document object, and then
* calculuating its digest using DatasetConfigXMLUtils.DEFAULTDIGESTALGORITHM.
* @param dsv -- A DatasetConfig object
* @return byte[] digest
* @throws ConfigurationException for all underlying Exceptions
*/
public byte[] getMessageDigestForDatasetConfig(DatasetConfig dsv) throws ConfigurationException {
return getMessageDigestForDocument(getDocumentForDatasetConfig(dsv));
}
/**
* This method does not convert the raw bytes of a given InputStream into a Message Digest. It is intended to calculate a Message Digest
* that is comparable between multiple XML representations of the same DatasetConfig Object (despite one representation having an Element with
* an Attribute specified with an empty string, and the other having the same Element with that Attribute specification missing entirely, or each
* containing the same Element with the same attribute specifications, but occuring in a different order within the XML string defining the Element).
* It does this by first converting the InputStream into a DatasetConfig Object (using XMLStreamToDatasetConfig(is)), and then calculating the
* digest on the resulting DatasetConfig Object (using DatasetConfigToMessageDigest(dsv, DatasetConfigXMLUtils.DEFAULTDIGESTALGORITHM)).
* @param xmlinput -- InputStream containing DatasetConfig.dtd compliant XML.
* @return byte[] digest
* @throws ConfigurationException for all underlying Exceptions
*/
public byte[] getMessageDigestForXMLStream(InputStream is) throws ConfigurationException {
return getMessageDigestForDocument(getDocumentForXMLStream(is));
}
/**
* Returns a byte[] of XML for the given DatasetConfig object.
* @param dsv - DatasetConfig object to be parsed into a byte[]
* @return byte[] representing XML for DatasetConfig
* @throws ConfigurationException for underlying exceptions
*/
public byte[] getByteArrayForDatasetConfig(DatasetConfig dsv) throws ConfigurationException {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
writeDatasetConfigToOutputStream(dsv, bout);
return bout.toByteArray();
}
}