toxgene.core.parser.ToxTemplate Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ToxGene Show documentation
Show all versions of ToxGene Show documentation
Modified ToXGene for the iBench project.
The newest version!
/**
* Parses a Tox-template document; creates the corresponding objects
* for dealing with the constructs in the template.
*
* @author Denilson Barbosa
* @version 0.1
*/
package toxgene.core.parser;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import java.util.Vector;
import java.io.InputStream;
import toxgene.core.Engine;
import toxgene.core.ToXgeneErrorException;
import toxgene.core.XML.XMLSchema;
import toxgene.core.factories.*;
import toxgene.core.genes.CreateGeneException;
import toxgene.core.genes.Gene;
import toxgene.core.genes.lists.ToxList;
import toxgene.core.genes.lists.WhereClause;
import toxgene.core.genes.literals.*;
import toxgene.core.genes.trees.*;
import toxgene.core.random.*;
import toxgene.interfaces.ToXgeneReporter;
import toxgene.util.Dictionary;
import toxgene.util.DuplicateKeyException;
import toxgene.util.KeyNotFoundException;
public class ToxTemplate {
/**
* This is the engine that runs one session of ToXgene. It contains
* all data necessary for producing the output.
*/
private Engine tgEngine;
private Dictionary simpleTypes, complexTypes, toxLists, toxFiles;
private Dictionary randomGenerators, simpleTypeFactories;
/**
* Contains the recursive descendants of a recursive element (i.e.,
* descendants with the same name as the recursive ancestor).
*/
private Vector recChildren;
private ToxValidatingParser parser;
public ToxTemplate(Engine engine, ToXgeneReporter reporter) {
tgEngine = engine;
}
public void buildTemplate(InputStream uri){
Document doc = null;
Node template, node;
String node_name;
try {
//we use this toxgene.core.parser class which validates the document againts the
//tox-gene DTD and trims the unnecessary #text elements
parser = new ToxValidatingParser(true, tgEngine.getToXgeneReporter());
doc = parser.parse(uri, true);
} catch (Exception e) {
throw new ToXgeneErrorException("template file could not be parsed: \n"
+ e.getMessage());
}
tgEngine.getToXgeneReporter().explain(uri + " parsed without problems.\n");
//Create the map for the simpleType factory objects
simpleTypeFactories = new Dictionary();
try {
simpleTypeFactories.add("string", new StringFactory(tgEngine));
simpleTypeFactories.add("integer", new IntegerFactory(
XMLSchema.INTEGER, tgEngine));
simpleTypeFactories.add("long", new IntegerFactory(XMLSchema.LONG,
tgEngine));
simpleTypeFactories.add("unsignedLong", new IntegerFactory(
XMLSchema.UNSIGNED_LONG, tgEngine));
simpleTypeFactories.add("int", new IntegerFactory(XMLSchema.INT,
tgEngine));
simpleTypeFactories.add("unsignedInt", new IntegerFactory(
XMLSchema.UNSIGNED_INT, tgEngine));
simpleTypeFactories.add("short",new IntegerFactory(XMLSchema.SHORT,
tgEngine));
simpleTypeFactories.add("unsignedShort", new IntegerFactory(
XMLSchema.SHORT, tgEngine));
simpleTypeFactories.add("byte", new IntegerFactory(XMLSchema.BYTE,
tgEngine));
simpleTypeFactories.add("nonNegativeInteger", new IntegerFactory(
XMLSchema.NON_NEGATIVE_INTEGER, tgEngine));
simpleTypeFactories.add("positiveInteger", new IntegerFactory(
XMLSchema.POSITIVE_INTEGER, tgEngine));
simpleTypeFactories.add("nonPositiveInteger", new IntegerFactory(
XMLSchema.NON_POSITIVE_INTEGER, tgEngine));
simpleTypeFactories.add("negativeInteger", new IntegerFactory(
XMLSchema.NEGATIVE_INTEGER, tgEngine));
simpleTypeFactories.add("decimal", new RealFactory(
XMLSchema.DECIMAL, tgEngine));
simpleTypeFactories.add("float", new RealFactory(XMLSchema.FLOAT,
tgEngine));
simpleTypeFactories
.add("double", new RealFactory(XMLSchema.DOUBLE, tgEngine));
simpleTypeFactories.add("date", new DateFactory(tgEngine));
//for compatibility reasons only
simpleTypeFactories.add("number", new RealFactory(XMLSchema.FLOAT,
tgEngine));
} catch (DuplicateKeyException e) {
}
//Create the maps for the types, lists, files...
simpleTypes = tgEngine.simpleTypes;
complexTypes = new Dictionary();
toxLists = tgEngine.toxLists;
toxFiles = tgEngine.toxFiles;
randomGenerators = tgEngine.randomGenerators;
template = doc.getDocumentElement();
NodeList children = template.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
node = children.item(i);
node_name = node.getNodeName();
if (node_name.compareTo("tox-distribution") == 0) {
processDistribution(node);
continue;
}
if (node_name.compareTo("simpleType") == 0) {
processSimpleType(node);
continue;
}
if (node_name.compareTo("complexType") == 0) {
processComplexType(node);
continue;
}
if (node_name.compareTo("tox-list") == 0) {
processToxList(node);
continue;
}
if (node_name.compareTo("tox-document") == 0) {
processToxFile(node);
}
}
//We're done.
tgEngine.getToXgeneReporter().explain("DONE processing template file.");
// doc = null;
};
public int findElement(Node node) {
try{
return parser.findElement(node);
}catch (Exception e){
return 0;
}
}
public Vector documents() {
return toxFiles.values();
}
public Vector lists() {
return toxLists.values();
}
public void deleteList(String name) {
try {
toxLists.remove(name);
} catch (KeyNotFoundException e) {
throw new ToXgeneErrorException("DIED A REALLY HORRIBLE DEATH");
}
}
/**
* Processes a named simpleType declaration.
*/
private void processSimpleType(Node node) {
Gene gene = null;
String name = "";
//SimpleType elements have only the 'name' attribute
try {
name = ((Element) node).getAttributeNode("name").getNodeValue();
} catch (NullPointerException e) {
throw new ToXgeneErrorException("\"name\" attribute required for "
+"simpleType.",findElement(node));
}
if (simpleTypes.contains(name)) {
throw new ToXgeneErrorException("simpleType \"" + name
+ "\" already declared!",
findElement(node));
}
Node restriction = ((Element) node).getFirstChild();
tgEngine.getToXgeneReporter().explain("Processing SimpleType: " + name);
//invokes the method for creating the gene for this type
if ((((Element) restriction).getElementsByTagName("tox-expr"))
.getLength() != 0) {
//this simple type has a scan/sample descendant
Node scanNode = restriction.getFirstChild();
String nodeName = scanNode.getNodeName();
if ((nodeName.compareTo("tox-scan") != 0)
&& (nodeName.compareTo("tox-sample") != 0)
&& (nodeName.compareTo("tox-foreach") != 0)) {
throw new ToXgeneErrorException("invalid simpleType declaration",
findElement(node));
}
gene = createToxScanGene(scanNode, null, true, null, 1, 1);
} else {
gene = createSimpleTypeGene(restriction);
}
//registers the gene in the list.
try {
simpleTypes.add(name, gene);
} catch (DuplicateKeyException e1) {
}
tgEngine.getToXgeneReporter().explain(" -----> done!");
}
/**
* Processes a named complex type declaration
*/
private void processComplexType(Node node) {
ToxComplexType complex;
//complexType elements have only a 'name' attribute
String name = ((Element) node).getAttributeNode("name").getNodeValue();
tgEngine.getToXgeneReporter().explain("Processing ComplexType: " + name);
String mixed = ((Element) node).getAttributeNode("mixed")
.getNodeValue();
//invokes the actual constructor for complexType genes. Null is used
//here because this complextype is not a descendant of any ToxScan node
if (mixed.compareTo("true") == 0) {
complex = createComplexType(node.getChildNodes(), null, null, true,
0, 0);
} else {
complex = createComplexType(node.getChildNodes(), null, null,
false, 0, 0);
}
try {
complexTypes.add(name, complex);
} catch (DuplicateKeyException e2) {
throw new ToXgeneErrorException("duplicate type declaration: " + name,
findElement(node));
}
tgEngine.getToXgeneReporter().explain("-----> done ComplexType: " + name);
}
/**
* Processes a tox-list declaration.
*/
private void processToxList(Node node) {
ToxList list = null;
//tox-lists have at least the 'name' attribute.
String name = ((Element) node).getAttributeNode("name").getNodeValue();
tgEngine.getToXgeneReporter().explain("Processing tox-list: " + name);
//The 'unique' attribute is optional
String unique = "";
try {
unique = ((Element) node).getAttributeNode("unique").getNodeValue();
} catch (NullPointerException e) {
}
//The 'where' attribute is optional
String where = "";
try {
where = ((Element) node).getAttributeNode("where").getNodeValue();
} catch (NullPointerException e) {
}
//the 'dump' attribute is mandatory (yes|no)
String dump = ((Element) node).getAttributeNode("dump").getNodeValue();
//get the gene for this list
Node root = node.getFirstChild();
ToxElement mygene = (ToxElement) createToxElementGene(root, null, null);
try {
String readFrom = ((Element) node).getAttributeNode("readFrom")
.getNodeValue();
String abort = ((Element) node).getAttributeNode("abort")
.getNodeValue();
list = new ToxList(name, mygene, unique, where,
(dump.compareTo("yes") == 0), readFrom,
(abort.compareTo("yes") == 0), findElement(node),
tgEngine);
} catch (NullPointerException e1) {
list = new ToxList(name, mygene, unique, where,
(dump.compareTo("yes") == 0), findElement(node),
tgEngine);
}
//registers the list in the system.
try {
toxLists.add(name, list);
} catch (DuplicateKeyException e3) {
throw new ToXgeneErrorException("duplicate tox-list declaration: "
+ e3.getMessage(),findElement(node));
}
//gets all lists referenced by this list gene
Vector references = getListReferences(mygene);
if (references != null) {
list.references(references);
}
tgEngine.getToXgeneReporter().explain("-----> done tox-list: " + name);
}
/**
* Processes a tox-file declaration
*/
private void processToxFile(Node node) {
ToxCollection file = null;
int copies = 0, start = 0;
//ToxFile elements have 'name' and 'copies' attributes
String name = ((Element) node).getAttributeNode("name").getNodeValue();
try {
copies = Integer.parseInt(((Element) node).getAttributeNode(
"copies").getNodeValue());
} catch (NumberFormatException e) {
throw new ToXgeneErrorException("invalid number of copies for file "
+ name, findElement(node));
}
if (copies < 1) {
copies = 1;
tgEngine.getToXgeneReporter().warning("number of copies is smaller than 1!\n"
+ "\tdefining copies = 1");
}
tgEngine.getToXgeneReporter().explain("Processing document: " + name);
//Let's get the root element in this document
Node root = ((Element) node).getFirstChild();
ToxElement gene = (ToxElement) createToxElementGene(root, null, null);
//check the starting number for indexing the files
try {
start = Integer.parseInt(((Element) node).getAttributeNode(
"starting-number").getNodeValue());
} catch (NumberFormatException e) {
throw new ToXgeneErrorException("invalid starting number for "
+"tox-document:" + name,
findElement(node));
} catch (NullPointerException e1) {
start = 0;
}
if (start < 0) {
start = 0;
tgEngine.getToXgeneReporter().warning("starting-number is negative! \n"
+ "\tdefining starting-number = 0");
}
//check whether we should pad leading 0's for the files names
boolean pad;
try {
pad = ((((Element) node).getAttributeNode("pad").getNodeValue())
.compareTo("yes") == 0);
} catch (NullPointerException e) {
pad = false;
tgEngine.getToXgeneReporter().warning("It seems you are using an outdated "
+"DTD for ToXgene templates. Please "
+"download the latest one.");
}
//check whether this toxFile has a DTD attached to it
try {
String dtd = ((Element) node).getAttributeNode("DTD-file")
.getNodeValue();
if (copies == 1)
file = new ToxCollection(name, gene, tgEngine.version());
else
file = new ToxCollection(name, copies, start, dtd, gene, pad,
tgEngine.version());
} catch (NullPointerException e) {
if (copies == 1)
file = new ToxCollection(name, gene, tgEngine.version());
else
file = new ToxCollection(name, copies, start, gene, pad,
tgEngine.version());
}
//register this tox-file in the list
try {
toxFiles.add(name, file);
} catch (DuplicateKeyException e2) {
throw new ToXgeneErrorException("duplicate document declaration: "
+ e2.getMessage(),
findElement(node));
}
//gets all lists referenced by this list gene
Vector references = getListReferences(gene);
if (references != null) {
file.references(references);
}
tgEngine.getToXgeneReporter().explain("-----> done tox-document: " + name);
}
/**
* Creates a new ToxRandom generator according to the probability
* distribution specified.
*/
private void processDistribution(Node node) {
ToxRandom rand = null;
//name, type, min and max are mandatory:
String name = ((Element) node).getAttributeNode("name").getNodeValue();
String type = ((Element) node).getAttributeNode("type").getNodeValue();
float min = (new Float(((Element) node)
.getAttributeNode("minInclusive").getNodeValue())).floatValue();
float max = (new Float(((Element) node)
.getAttributeNode("maxInclusive").getNodeValue())).floatValue();
if (type.compareTo("uniform") == 0) {
rand = tgEngine.newUniformDistribution(min, max);
}
if (type.compareTo("normal") == 0) {
try {
float mean = (new Float(((Element) node).getAttributeNode(
"mean").getNodeValue())).floatValue();
float var = (new Float(((Element) node).getAttributeNode(
"variance").getNodeValue())).floatValue();
rand = tgEngine.newGaussianDistribution(min, max, mean, var);
} catch (NullPointerException e1a) {
throw new ToXgeneErrorException("Invalid gaussian distribution "
+"specification!",findElement(node));
}
catch (CreateGeneException cg1){
throw new ToXgeneErrorException(cg1.getMessage(),findElement(node));
}
}
if (type.compareTo("lognormal") == 0) {
try {
float mean = (new Float(((Element) node).getAttributeNode(
"mean").getNodeValue())).floatValue();
float var = (new Float(((Element) node).getAttributeNode(
"variance").getNodeValue())).floatValue();
rand = tgEngine.newLogNormalDistribution(min, max, mean, var);
} catch (NullPointerException e1) {
throw new ToXgeneErrorException("Invalid lognormal distribution "
+"specification!",findElement(node));
}
catch (CreateGeneException cg1){
throw new ToXgeneErrorException(cg1.getMessage(),findElement(node));
}
}
if (type.compareTo("exponential") == 0) {
try {
float mean = (new Float(((Element) node).getAttributeNode(
"mean").getNodeValue())).floatValue();
rand = tgEngine.newExponentialDistribution(min, max, mean);
} catch (NullPointerException e1) {
throw new ToXgeneErrorException("Invalid exponential distribution "
+"specification!",findElement(node));
}
catch (CreateGeneException cg1){
throw new ToXgeneErrorException(cg1.getMessage(),findElement(node));
}
}
if (type.compareTo("geometric") == 0) {
try {
float mean = (new Float(((Element) node).getAttributeNode(
"mean").getNodeValue())).floatValue();
rand = tgEngine.newGeometricDistribution(min, max, mean);
} catch (NullPointerException e1) {
throw new ToXgeneErrorException("Invalid geometric distribution "
+"specification!",findElement(node));
}
catch (CreateGeneException cg1){
throw new ToXgeneErrorException(cg1.getMessage(),findElement(node));
}
}
if (type.compareTo("constant") == 0) {
if (min != max) {
tgEngine.getToXgeneReporter().warning("different minInclusive and "
+"maxInclusive values "
+"for constant\ndistribution \""
+name
+"\" (line "+findElement(node)
+"). Using minInclusive.");
}
try{
rand = tgEngine.newConstantDistribution(min);
}
catch (CreateGeneException cg1){
throw new ToXgeneErrorException(cg1.getMessage(),findElement(node));
}
}
if (type.compareTo("user-defined") == 0) {
rand = new ToxUserDefined(min, max, tgEngine.nextRandomSeed());
NodeList children = node.getChildNodes();
float sum = 0;
for (int i = 0; i < children.getLength(); i++) {
Element element = (Element) children.item(i);
float value = 0, percent = 0;
try {
value = Float.parseFloat(element.getAttributeNode("value").
getNodeValue());
percent = Float.parseFloat(element.getAttributeNode("tox-percent").
getNodeValue());
} catch (NumberFormatException e1) {
throw new ToXgeneErrorException(
"could not parse floating point numbers for user "
+ "defined-distribution" + name, findElement(node));
}
sum += percent;
if (sum > 100.0) {
throw new ToXgeneErrorException("probability mass adds to more than "
+"100!",findElement(node));
} else {
((ToxUserDefined) rand).addOption(value, percent);
}
}
}
//register this random generator
try {
randomGenerators.add(name, rand);
} catch (DuplicateKeyException e2) {
//we know this can't happen since name is an ID for the element!
}
}
/**
* Extracts all lists that are referenced in the given gene. This
* information is used for garbage collection purposes. This function is
* only called from processToxList and processToxFile, thus we can pass a
* ToxElement along.
*/
private Vector getListReferences(TreeGene gene) {
Vector result = null;
Vector children = gene.children();
int size = children == null ? 0 : children.size();
for (int i = 0; i < size; i++) {
try {
TreeGene temp = (TreeGene) children.get(i);
if (temp instanceof ToxScan) {
if (result == null) {
result = new Vector();
}
result.add(((ToxScan) temp).list());
}
Vector temp2 = getListReferences(temp);
if (temp2 != null) {
if (result == null) {
result = new Vector();
}
result.addAll(temp2);
}
} catch (ClassCastException e) {
//this will occur with literal Genes
continue;
}
}
return result;
}
/**
* This method creates a new Gene from a simpleType definition.
*/
private Gene createSimpleTypeGene(Node restriction) {
String base;
SimpleTypeFactory factory;
//find out the base type for this gene
base = ((Element) restriction).getAttributeNode("base").getNodeValue();
try {
//use the proper gene factory
factory = (SimpleTypeFactory) simpleTypeFactories.get(base);
try {
return (factory.createGene(restriction.getChildNodes()));
}
catch (CreateGeneException e) {
throw new ToXgeneErrorException("invalid simpleType defintion: " +
e.getMessage(),
findElement(restriction));
}
}
catch (KeyNotFoundException e1) {
throw new ToXgeneErrorException("cannot find type \"" + base
+ "\" definition",
findElement(restriction));
}
}
/**
* Processes the three primitive genes in ToXgene: tox-string, tox-number
* and tox-value. Throws an exception if the gene is not recognized.
*
* Primitive nodes have no other genes as their descendants, so we do not
* care about tox-lookups here (the calling method will do that).
*/
private Gene createPrimitiveGene(Node node) throws Exception {
String content = node.getNodeName();
String base = "string"; //this is the default factory to be used
SimpleTypeFactory factory;
if (content.compareTo("tox-number") == 0) {
base = "float";
}
try {
//use the proper gene factory
factory = (SimpleTypeFactory) simpleTypeFactories.get(base);
return (factory.createGene(node));
} catch (KeyNotFoundException e) {
}
return null;
}
/**
* Creates a container for a complex type definition taking lookup and
* lookup items into consideration.
*
* nodes is the content of the complex type. lookup is the closest lookup
* ancestor (if any), for which all lookupitems refer to. recursive is the
* closest recursively defined ancestor (if any) hasMixedContent specifies
* whether mixed content is allowed in this type min_qtty and max_qtty are
* the minimum and maximum number of occurrences for the closest ancestor of
* this complexType
*/
private ToxComplexType createComplexType(NodeList nodes, ToxScan scan,
String recursive, boolean hasMixedContent, int min_qtty,
int max_qtty) {
ToxComplexType holder = new ToxComplexType();
String node_name, name, type;
Gene gene;
/**
* determines whether the complex object has CDATA content
*/
boolean hasCDATA = false;
/**
* determines whether the complex object has sub-elements
*/
boolean hasElement = false;
//scan through all elements in this complex type definition at the
// first
//level only.
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
node_name = node.getNodeName();
if (node_name.compareTo("attribute") == 0) {
gene = createToxAttributeGene(node, scan);
holder.addAttribute(gene);
continue;
}
if (node_name.compareTo("element") == 0) {
//consistency check
if (!hasMixedContent && hasCDATA) {
throw new ToXgeneErrorException("mixed content not allowed for "
+ "element in complex type declaration!", findElement(node));
}
//createToxElementGene does all the job for us here
gene = createToxElementGene(node, scan, recursive);
holder.addContent(gene);
hasElement = true;
continue;
}
if (node_name.compareTo("tox-scan") == 0) {
ToxScan myScan = createToxScanGene(node, scan, hasMixedContent,
recursive, min_qtty, max_qtty);
if (myScan.hasAttributes()) {
holder.addContainer(myScan);
}
holder.addScan(myScan);
continue;
}
if (node_name.compareTo("tox-sample") == 0) {
ToxScan myScan = createToxScanGene(node, scan, hasMixedContent,
recursive, min_qtty, max_qtty);
if (myScan.hasAttributes()) {
holder.addContainer(myScan);
}
holder.addScan(myScan);
continue;
}
if (node_name.compareTo("tox-foreach") == 0) {
ToxScan myScan = createToxScanGene(node, scan, hasMixedContent,
recursive, min_qtty, max_qtty);
if (myScan.hasAttributes()) {
holder.addContainer(myScan);
}
holder.addScan(myScan);
continue;
}
if (node_name.compareTo("tox-alternatives") == 0) {
ToxAlternatives alt = createToxAlternativesGene(node, scan,
recursive, hasMixedContent, min_qtty, max_qtty);
if (alt.hasAttributes()) {
holder.addContainer(alt);
}
holder.addContent(alt);
continue;
}
if (node_name.compareTo("tox-if") == 0) {
ToxIf ifgene = createToxIfGene(node, scan, recursive,
hasMixedContent, min_qtty, max_qtty);
if (ifgene.hasAttributes()) {
holder.addContainer(ifgene);
}
holder.addContent(ifgene);
continue;
}
if (node_name.compareTo("tox-expr") == 0) {
ToxGet tget = createToxGetGene(node, scan, min_qtty, max_qtty);
holder.addContent(tget);
if (tget.getType().compareTo("complex") != 0) {
hasCDATA = true;
}
continue;
}
// a last resource: this could be a primitive gene or a lookup-item
// which do not have to know about tox-lookups!!!
try {
gene = createPrimitiveGene(node);
holder.addContent(gene);
hasCDATA = true;
continue;
} catch (Exception e) {
throw new ToXgeneErrorException("invalid type declaration!",
findElement(node));
}
}
return holder;
}
/**
* Creates a Gene for a (simple or complex) element.
*/
private Gene createToxElementGene(Node element, ToxScan scan,
String recursive) {
String name, type, distribution = "", int_scan;
int min_qtty = 0, max_qtty = 0, min_occurs = 0, max_occurs = 0;
//this is the element to be returned
ToxElement elementGene = null;
//random generators are passed from parent to child nodes.
ToxRandom myRandom = null;
String myRecursive = recursive;
//name, type, minOccurs and maxOccurs are mandatory
name = new String(((Element) element).getAttributeNode("name")
.getNodeValue());
min_occurs = Integer.parseInt(((Element) element).getAttributeNode(
"minOccurs").getNodeValue());
int_scan = ((Element) element).getAttributeNode("maxOccurs")
.getNodeValue();
if (int_scan.compareTo("unbounded") != 0) {
max_occurs = Integer.parseInt(int_scan);
} else {
max_occurs = -1;
}
tgEngine.getToXgeneReporter().explain("Processing element: " + name + ", minOccurs: "
+ min_occurs + ", maxOccurs: " + max_occurs);
//check whether the genes of this element have to be reset each time
// the
//gene is instantiated.
boolean resetElement = false;
try {
String reset = ((Element) element).getAttributeNode("tox-reset")
.getNodeValue();
resetElement = (reset.compareTo("yes") == 0);
} catch (Exception e) {
tgEngine.getToXgeneReporter().warning("it seems your template referencess an outdated DTD.\n"
+ "Some ToXgene features cannot work properly unless "
+ "you use the latest DTD.\n");
}
/**
* tox-omitTag is used to indicate we are generating recursive mixe
* content.
*/
boolean omitTag = false;
try {
String reset = ((Element) element).getAttributeNode("tox-omitTag")
.getNodeValue();
omitTag = (reset.compareTo("yes") == 0);
} catch (Exception e) {
tgEngine.getToXgeneReporter().warning("it seems your template refers to an"
+" outdated DTD.\nSome ToXgene features "
+"will not work properly unless "
+ "you use the latest DTD.\n");
}
/**
* The number of occurrences of an element is either randomly generated,
* for which we can : 1. use the one specified in a tox-distribution
* attribute 2. create one from min_qtty and max_qtty;
*
* or it is "unbounded" (in this case we *require* both min_qtty and
* max_qtty to be defined): it will be read from a tox-list later on.
*/
try {
distribution = ((Element) element).getAttributeNode(
"tox-distribution").getNodeValue();
myRandom = (ToxRandom) randomGenerators.get(distribution);
min_qtty = (int) myRandom.minValue();
max_qtty = (int) myRandom.maxValue();
} catch (NullPointerException e4) {
//this means the element has no random generator specified
min_qtty = min_occurs;
max_qtty = max_occurs;
if (max_occurs > 0 && max_occurs < min_occurs) {
max_occurs = min_occurs;
tgEngine.getToXgeneReporter().warning("maxOccurs smaller than minOccurs "
+"for element: "+ name
+ ". Defining maxOccurs = "
+ min_occurs+ ".");
}
if (max_qtty != -1) {
if (min_occurs == max_occurs) {
//this is more common than we think
myRandom = tgEngine.newConstantDistribution(min_occurs);
} else {
//this is the default case, uniform distribution
myRandom = tgEngine.newUniformDistribution(min_occurs, max_occurs);
}
}
} catch (KeyNotFoundException e3) {
//this means that the tox-distribution is invalid
throw new ToXgeneErrorException("undefined tox-distribution " +
distribution+ " in element\"" + name
+ "\"", findElement(element));
}
//simple integrity checks
if (min_qtty < min_occurs) {
throw new ToXgeneErrorException("element "+name+" cannot occur less "
+"than "+ min_occurs+ " times!",
findElement(element));
}
if (max_occurs != -1 && max_qtty > max_occurs) {
tgEngine.getToXgeneReporter().warning("maxOccurs for element \"" + name
+ "\" is smaller than "
+ "value defined by maxInclusive in distribution "
+ distribution);
}
// At this point we have to check whether this is a recursive
// element. If so, the actual gene was processed before.
ToxRecursiveElement recChild = null;
boolean isRecChild = false;
if ((recursive != null) && (name.compareTo(recursive) == 0)) {
if (recChildren == null) {
recChildren = new Vector();
}
recChild = new ToxRecursiveElement(min_qtty, max_qtty, myRandom,
name);
recChildren.add(recChild);
isRecChild = true;
tgEngine.getToXgeneReporter().explain("Processing recursive descendant of: " + name);
}
// Another option: this is the ancestor recursive element, we have to
// keep its gene for when we get to the descendant, which is taken care
// of with the previous code block
boolean isRecAncestor = false;
ToxRandom recLevels = null;
String recD = null;
try {
recD = ((Element) element).getAttributeNode("tox-recursionLevels")
.getNodeValue();
tgEngine.getToXgeneReporter().explain("Processing recursive element: " + name);
recLevels = (ToxRandom) tgEngine.randomGenerators.get(recD);
//only one recursive element at a time
if (myRecursive != null) {
throw new ToXgeneErrorException("cannot have recursive element: "
+recD+" nested within other recursive"
+" element: "+ myRecursive,
findElement(element));
}
isRecAncestor = true;
myRecursive = name;
tgEngine.getToXgeneReporter().explain("-----> done recursive element");
} catch (KeyNotFoundException e) {
try {
int l = Integer.parseInt(recD);
recLevels = tgEngine.newUniformDistribution(0, l);
isRecAncestor = true;
myRecursive = name;
tgEngine.getToXgeneReporter().explain("-----> done recursive element");
} catch (NumberFormatException e1) {
throw new ToXgeneErrorException("invalid recursive element \""
+ name
+ "\":\n cannot find tox-distribution named with or "
+ "parse an integer from \"" + recD + "\"",
findElement(element));
}
} catch (NullPointerException e2) {
//fine, no recursionLevel was specified.
}
if (!element.hasChildNodes()) {
//find the type of the element, if registered, or create a new one
try {
type = ((Element) element).getAttributeNode("type")
.getNodeValue();
try {
//try to get a simpleType for this element
Gene t = (Gene) simpleTypes.get(type);
if (isRecChild) {
recChild.addBackup(t);
return (Gene) recChild;
} else {
if (omitTag) {
elementGene =
new ToxRecursiveMixedContent(min_qtty, max_qtty, myRandom,
true, resetElement,
tgEngine.addNewLines());
} else {
elementGene = new ToxElement(name, min_qtty, max_qtty, myRandom,
true, resetElement, isRecAncestor,
tgEngine);
}
elementGene.addContent(t);
}
} catch (KeyNotFoundException e1) {
try {
//it can be a complexType then
ToxComplexType complex = (ToxComplexType) complexTypes
.get(type);
//create the gene for the element
if (omitTag) {
elementGene =
new ToxRecursiveMixedContent(min_qtty, max_qtty, myRandom,
false,resetElement,
tgEngine.addNewLines());
} else {
elementGene = new ToxElement(name, min_qtty, max_qtty, myRandom,
false, resetElement, isRecAncestor,
tgEngine);
}
elementGene.addComplexType(complex);
} catch (KeyNotFoundException e2) {
try {
SimpleTypeFactory factory=
(SimpleTypeFactory) simpleTypeFactories.get(type);
//create the gene for the element
if (omitTag) {
elementGene =
new ToxRecursiveMixedContent(min_qtty, max_qtty, myRandom,
true,resetElement,
tgEngine.addNewLines());
} else {
elementGene = new ToxElement(name, min_qtty, max_qtty,myRandom,
true, resetElement,isRecAncestor,
tgEngine);
}
elementGene.addContent(factory.createGene());
} catch (KeyNotFoundException e3) {
//now we must give up
throw new ToXgeneErrorException("Cannot find type \"" + type + "\"",
findElement(element));
}
}
}
} catch (NullPointerException e3) {
if (isRecChild) {
return (Gene) recChild;
}
throw new ToXgeneErrorException("no type specified for element \""
+ name + "\"", findElement(element));
}
return (Gene) elementGene;
} else {
//the element type is declared by its children. If a "type"
// attribute is
//provied, it is overriden.
Node node = element.getFirstChild();
String elmType = node.getNodeName();
if (elmType.compareTo("simpleType") == 0) {
//create the gene for the element
if (omitTag) {
elementGene =
new ToxRecursiveMixedContent(min_qtty, max_qtty, myRandom, true,
resetElement, tgEngine.addNewLines());
} else {
elementGene = new ToxElement(name, min_qtty, max_qtty,myRandom, true,
resetElement, isRecAncestor, tgEngine);
}
tgEngine.getToXgeneReporter().explain("Processing anonymous SimpleType in: " + name);
//we can call createSimpleTypeGene here
Node restriction = node.getFirstChild();
if ((((Element) restriction).getElementsByTagName("tox-expr"))
.getLength() != 0) {
//this simple type has a scan/sample descendant
Node scanNode = restriction.getFirstChild();
String nodeName = scanNode.getNodeName();
if ((nodeName.compareTo("tox-scan") != 0)
&& (nodeName.compareTo("tox-sample") != 0)
&& (nodeName.compareTo("tox-foreach") != 0)) {
throw new ToXgeneErrorException("invalid simpleType declaration",
findElement(restriction));
}
ToxScan myScan = createToxScanGene(scanNode, scan, true,
null, min_qtty, max_qtty);
elementGene.addScan(myScan);
} else {
elementGene.addContent(createSimpleTypeGene(restriction));
}
tgEngine.getToXgeneReporter().explain("-----> done SimpleType in: " + name);
return (Gene) elementGene;
}
if (elmType.compareTo("complexType") == 0) {
//create the gene for the element
if (omitTag) {
elementGene =
new ToxRecursiveMixedContent(min_qtty, max_qtty, myRandom, false,
resetElement, tgEngine.addNewLines());
} else {
elementGene = new ToxElement(name, min_qtty, max_qtty,myRandom,false,
resetElement, isRecAncestor,tgEngine);
}
//here we create a new ToxComplexType
tgEngine.getToXgeneReporter().explain("Processing anonymous ComplexType in: " + name);
String mixed = ((Element) node).getAttributeNode("mixed")
.getNodeValue();
if (mixed.compareTo("true") == 0) {
elementGene.addComplexType(createComplexType(node
.getChildNodes(), scan, myRecursive, true,
min_qtty, max_qtty));
} else {
elementGene.addComplexType(createComplexType(node
.getChildNodes(), scan, myRecursive, false,
min_qtty, max_qtty));
}
tgEngine.getToXgeneReporter().explain("-----> done ComplexType in: " + name);
if (isRecAncestor) {
try {
for (int i = 0; i < recChildren.size(); i++) {
ToxRecursiveElement child = (ToxRecursiveElement) recChildren
.get(i);
child.setContent(elementGene, recLevels,
recChildren);
}
} catch (NullPointerException e) {
tgEngine.getToXgeneReporter().warning("no recursive descendant for element: "
+ name + " was found.");
}
recChildren = null;
}
return (Gene) elementGene;
}
if (elmType.compareTo("tox-expr") == 0) {
ToxGet get = createToxGetGene(node, scan, min_qtty, max_qtty);
if (isRecChild) {
recChild.addBackup(get);
return (Gene) recChild;
}
if (omitTag) {
elementGene =
new ToxRecursiveMixedContent(min_qtty, max_qtty, myRandom, true,
resetElement, tgEngine.addNewLines());
} else {
elementGene = new ToxElement(name, min_qtty, max_qtty,myRandom, true,
resetElement, isRecAncestor, tgEngine);
}
elementGene.addVarQttyContent(get);
return (Gene) elementGene;
}
}
throw new ToXgeneErrorException("invalid element definition:" + name,
findElement(element));
}
/**
* Creates a gene for an attribute declaration
*/
private Gene createToxAttributeGene(Node node, ToxScan scan) {
Gene gene = null;
ToxAttribute attribute = null;
String name, distribution = "", type = "", int_scan;
char separator = 0;
ToxRandom myRandom = null;
int min_qtty = 0, max_qtty = 0;
boolean get_max_qtty = false;
//attribute nodes have name, tox-minqtty and tox-maxqtty as required
//attributes. Optionally, they have a tox-distribution and a type
//declaration
name = ((Element) node).getAttributeNode("name").getNodeValue();
tgEngine.getToXgeneReporter().explain("Processing attribute: " + name);
try {
distribution = ((Element) node)
.getAttributeNode("tox-distribution").getNodeValue();
myRandom = (ToxRandom) randomGenerators.get(distribution);
min_qtty = (int) myRandom.minValue();
max_qtty = (int) myRandom.maxValue();
} catch (KeyNotFoundException e1) {
throw new ToXgeneErrorException("Invalid distribution name: "
+ distribution,findElement(node));
} catch (NullPointerException e2) {
int_scan = ((Element) node).getAttributeNode("tox-minOccurs")
.getNodeValue();
min_qtty = Integer.parseInt(int_scan);
int_scan = ((Element) node).getAttributeNode("tox-maxOccurs")
.getNodeValue();
if (int_scan.compareTo("unbounded") != 0) {
max_qtty = Integer.parseInt(int_scan);
myRandom = tgEngine.newUniformDistribution(min_qtty, max_qtty);
} else {
max_qtty = -1;
}
}
try {
String temp = ((Element) node).getAttributeNode("tox-distribution")
.getNodeValue();
if (temp.length() != 1) {
throw new ToXgeneErrorException("Invalid separator \"" + temp
+ "\" for multivalued " + "attribute!");
}
separator = temp.charAt(0);
} catch (NullPointerException e) {
//do nothing, no separator was specified.
}
if (node.hasChildNodes()) {
//the gene of this attribute is specified by its children, here we
// can
//have one of or
Node child = node.getFirstChild();
if (child.getNodeName().compareTo("tox-expr") == 0) {
gene = createToxGetGene(child, scan, min_qtty, max_qtty);
get_max_qtty = true;
} else {
if (child.getNodeName().compareTo("simpleType") == 0) {
Node restriction = child.getFirstChild();
if ((((Element) restriction)
.getElementsByTagName("tox-expr")).getLength() != 0) {
//this simple type has a scan/sample descendant
Node scanNode = restriction.getFirstChild();
String nodeName = scanNode.getNodeName();
if ((nodeName.compareTo("tox-scan") != 0)
&& (nodeName.compareTo("tox-sample") != 0)
&& (nodeName.compareTo("tox-foreach") != 0)) {
throw new ToXgeneErrorException("invalid simpleType declaration",
findElement(restriction));
}
ToxScan myScan = createToxScanGene(scanNode, scan,
true, null, min_qtty, max_qtty);
gene = myScan;
get_max_qtty = true;
} else {
gene = createSimpleTypeGene(restriction);
}
}
}
} else {
//this attribute element has to have its gene specified by the type
//attribute
try {
type = ((Element) node).getAttributeNode("type").getNodeValue();
gene = (Gene) simpleTypes.get(type);
} catch (KeyNotFoundException e1) {
//the type provided is not a user-defined simpleType, it could
// be a
//base type, for which a standard gene is used
try {
SimpleTypeFactory factory = (SimpleTypeFactory) simpleTypeFactories
.get(type);
gene = factory.createGene(node.getChildNodes());
} catch (KeyNotFoundException e2) {
//this is an invalid type declaration!
throw new ToXgeneErrorException("invalid \"" + name
+ "\" attribute declaration: " + e2.getMessage(),
findElement(node));
}
} catch (NullPointerException e1) {
//no type information provided, this attribute is either
// anonymous or
//has a tox-expr as its contents.
throw new ToXgeneErrorException("invalid \"" + name
+ "\" attribute declaration: no type" + " specified",
findElement(node));
}
}
attribute = new ToxAttribute(name, min_qtty, max_qtty, gene, myRandom,
get_max_qtty, separator);
tgEngine.getToXgeneReporter().explain("-----> done attribute: " + name);
return attribute;
}
/**
* Creates a gene for a tox-expr element
*/
private ToxGet createToxGetGene(Node node, ToxScan scan, int min, int max) {
ToxGet gene = null;
String query = "", format = "";
try {
query = ((Element) node).getAttributeNode("value").getNodeValue();
} catch (NullPointerException e) {
throw new ToXgeneErrorException("no query specified for tox-expr item!",
findElement(node));
}
try {
format = ((Element) node).getAttributeNode("format").getNodeValue();
} catch (NullPointerException e) {
}
tgEngine.getToXgeneReporter().explain("Processing tox-expr for: " + query);
gene = new ToxGet(ExpressionParser.parse(query, scan, findElement(node),
tgEngine.getToXgeneReporter(),
tgEngine.simpleTypes()),
min, max, format, tgEngine);
return gene;
}
/**
* Creates a gene for a tox-alternatives element
*/
private ToxAlternatives createToxAlternativesGene(Node node, ToxScan scan,
String recursive, boolean mixed, int min_qtty, int max_qtty) {
ToxAlternatives gene;
ToxComplexType complex = null;
ToxOption option = null;
ToxRandom myRandom = null;
NodeList children = node.getChildNodes();
Node child;
tgEngine.getToXgeneReporter().explain("Processing tox-alternatives:");
try {
String distribution = ((Element) node).getAttributeNode(
"tox-distribution").getNodeValue();
myRandom = (ToxRandom) randomGenerators.get(distribution);
int min = (int) myRandom.minValue();
int max = (int) myRandom.maxValue();
if (min < 0 || max > 100) {
throw new ToXgeneErrorException("the probability distribution for "
+ "choosing among alternatives has to be in [0,100]",
findElement(node));
}
if (min != 0 || max != 100) {
tgEngine.getToXgeneReporter().warning("probabiliy distribution != [0,100]!\n"
+ "\tno action taken");
}
} catch (KeyNotFoundException e1) {
throw new ToXgeneErrorException("invalid distribution name: ",
findElement(node));
} catch (NullPointerException e2) {
myRandom = tgEngine.newUniformDistribution(0, 100);
}
gene = new ToxAlternatives(myRandom);
for (int i = 0; i < children.getLength(); i++) {
child = children.item(i);
if (child.getNodeName().compareTo("tox-option") == 0) {
//retrieves the probability of occurrence for this option
Float percent = new Float(((Element) child).getAttributeNode(
"odds").getNodeValue());
tgEngine.getToXgeneReporter().explain("Processing tox-option; odds = " + percent);
//create the gene for this option
option = new ToxOption();
complex = createComplexType(child.getChildNodes(), scan,
recursive, mixed, min_qtty, max_qtty);
Vector temp1 = complex.contents();
for (int j = 0; j < temp1.size(); j++) {
option.addElement((Gene) temp1.elementAt(j));
}
Vector temp2 = complex.attributes();
for (int j = 0; j < temp2.size(); j++) {
option.addAttribute((Gene) temp2.elementAt(j));
}
gene.addOption(percent.floatValue(), option);
tgEngine.getToXgeneReporter().explain("-----> done tox-option");
}
}
tgEngine.getToXgeneReporter().explain("-----> done tox-alternatives");
return gene;
}
/**
* Creates a gene for a tox-alternatives element
*/
private ToxIf createToxIfGene(Node node, ToxScan scan, String recursive,
boolean mixed, int min_qtty, int max_qtty) {
ToxIf gene;
ToxComplexType complex = null;
ToxOption thenBlock = null, elseBlock = null;
NodeList children = node.getChildNodes();
Node child;
tgEngine.getToXgeneReporter().explain("Processing tox-if:");
if (scan == null) {
throw new ToXgeneErrorException(
"tox-if declared out of tox-scan/tox-sample/tox-foreach "
+ "scope!", findElement(node));
}
String exp = ((Element) node).getAttributeNode("expr").getNodeValue();
//the first child of a tox-if is a tox-then element
child = children.item(0);
tgEngine.getToXgeneReporter().explain("Processing tox-then clause");
//create the gene for this option
thenBlock = new ToxOption();
complex = createComplexType(child.getChildNodes(), scan, recursive,
mixed, min_qtty, max_qtty);
Vector temp1 = complex.contents();
for (int j = 0; j < temp1.size(); j++) {
thenBlock.addElement((Gene) temp1.elementAt(j));
}
temp1 = complex.attributes();
for (int j = 0; j < temp1.size(); j++) {
thenBlock.addAttribute((Gene) temp1.elementAt(j));
}
tgEngine.getToXgeneReporter().explain("-----> done tox-then");
gene = new ToxIf(new WhereClause(exp, scan, findElement(node),
tgEngine.getToXgeneReporter(),
tgEngine.simpleTypes()),
thenBlock);
//the else child is optional
if (children.getLength() == 2) {
child = children.item(1);
tgEngine.getToXgeneReporter().explain("Processing tox-else clause");
//create the gene for this option
elseBlock = new ToxOption();
complex = createComplexType(child.getChildNodes(), scan, recursive,
mixed, min_qtty, max_qtty);
temp1 = complex.contents();
for (int j = 0; j < temp1.size(); j++) {
elseBlock.addElement((Gene) temp1.elementAt(j));
}
temp1 = complex.attributes();
for (int j = 0; j < temp1.size(); j++) {
elseBlock.addAttribute((Gene) temp1.elementAt(j));
}
tgEngine.getToXgeneReporter().explain("-----> done tox-else");
gene.addElseBlock(elseBlock);
}
tgEngine.getToXgeneReporter().explain("-----> done tox-if");
return gene;
}
private ToxScan createToxScanGene(Node node, ToxScan master,
boolean hasMixedContent, String recursive, int min_qtty,
int max_qtty) {
ToxScan myScan;
boolean isSample = (node.getNodeName().compareTo("tox-sample") == 0);
boolean isForeach = (node.getNodeName().compareTo("tox-foreach") == 0);
ToxRandom myRandom = null;
String path = "", duplicates = "", varName = "", where = "";
path = ((Element) node).getAttributeNode("path").getNodeValue();
if (isSample) {
tgEngine.getToXgeneReporter().explain("Processing tox-sample: ");
} else {
if (isForeach) {
tgEngine.getToXgeneReporter().explain("Processing tox-foreach: ");
} else {
tgEngine.getToXgeneReporter().explain("Processing tox-scan: ");
}
}
try {
varName = ((Element) node).getAttributeNode("name").getNodeValue();
} catch (NullPointerException e) {
}
try {
where = ((Element) node).getAttributeNode("where").getNodeValue();
} catch (NullPointerException e) {
}
if (isSample) {
duplicates = ((Element) node).getAttributeNode("duplicates")
.getNodeValue();
//get a user defined distribution
try {
String distribution = ((Element) node).getAttributeNode(
"tox-distribution").getNodeValue();
myRandom = (ToxRandom) randomGenerators.get(distribution);
if (myRandom.minValue() != 0) {
tgEngine.getToXgeneReporter().warning("minimum value in distribution "
+ distribution + " != 0.\n Some elements in "
+ path + " might never be accessed!");
}
} catch (NullPointerException e) {
}
}
if (isSample) {
tgEngine.getToXgeneReporter().explain("path: " + path + " duplicates: " + duplicates);
} else {
tgEngine.getToXgeneReporter().explain("path: " + path);
}
myScan = new ToxScan(path, master, varName, isForeach, isSample,
duplicates.compareTo("yes") == 0, myRandom, where,
findElement(node), tgEngine);
//process all the children of this element
NodeList children = node.getChildNodes();
ToxComplexType myHolder = createComplexType(children, myScan,
recursive, hasMixedContent, min_qtty, max_qtty);
myScan.addComplexType(myHolder);
return myScan;
}
};