
toxgene.core.parser.ToxTemplate Maven / Gradle / Ivy
/**
* 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;
}
};
© 2015 - 2025 Weber Informatics LLC | Privacy Policy