
toxgene.core.genes.trees.ToxElement Maven / Gradle / Ivy
/**
* Provides an inteface to the basic building block of XML documents (the
* elements).
*
* @author Denilson Barbosa
* @version 0.1 */
package toxgene.core.genes.trees;
import java.io.PrintStream;
import java.util.Vector;
import toxgene.core.Engine;
import toxgene.core.ToXgeneErrorException;
import toxgene.core.genes.*;
import toxgene.core.genes.lists.ListGene;
import toxgene.core.genes.lists.ToxList;
import toxgene.core.genes.lists.ToxListElement;
import toxgene.core.genes.lists.ToxListElementException;
import toxgene.core.genes.literals.LiteralGene;
import toxgene.core.parser.ToxComplexType;
import toxgene.core.random.ToxRandom;
public class ToxElement implements TreeGene, ListGene {
/**
* Tag name for the element.
*/
private String tagname;
/**
* Minimum and maximun numbers of occurrences for actual instances
*/
private int min_qtty, max_qtty;
/**
* determines whether this element has a predefined upper limit on its
* number of occurrences (i.e., max_qtty).
*/
private boolean get_max_qtty = false;
/**
* Pseudo-random number generator
*/
private ToxRandom randomGenerator;
/**
* Vector with all direct attributes of the element.
*/
private Vector attributes;
/**
* Vector for the genes that define the contents of the element,
* regardless of its content model.
*/
private Vector contents;
/**
* Vector with all container objects inside this element. Container
* objects contain attributes and other elements that might or might not
* be generated, depending on factors external to this element.
*/
private Vector containers;
/**
* Vector with all genes that have variable number of occurrences. These
* genes determine the actual number of occurrences of the current
* element. Each element in this vector is also in the contents vector
* (inserted in the correct order of appearence in the input template) and
* is generated like any other gene.
*/
private Vector varQttyContents;
/**
* Vector with all tox-scan elements that are direct children of this
* elment, used to reset them before generating any data. Each element in
* this vector is also in the varQttyContents (thus also in the contents)
* vector.
*/
private Vector scans;
/**
* Determines whether this element is a literal or a tree gene.
*/
private boolean isLiteral;
/**
* Determines whether this gene's contents have to be reset each time the
* gene is instantiated.
*/
private boolean resetGenes;
/**
* Determines whether this element is the recursive ancestor of another.
* If not, the element is "memoryless"
*/
private boolean isRecursiveAncestor;
/**
* Number of times the gene will be instantiated.
*/
private int times;
/**
* Number of times the gene was already instantiaded.
*/
private int instance;
/**
* ToXgene engine...
*/
private Engine tgEngine;
public ToxElement() {
//do nothing. Defined so that ToxRecursiveMixedContent will compile
}
public ToxElement(String tagname, int min_qtty, int max_qtty,
ToxRandom randomGenerator,boolean isLiteral,
boolean resetGenes, boolean isRecursiveAncestor,
Engine engine) {
this.tagname = tagname;
this.min_qtty = min_qtty;
this.max_qtty = max_qtty;
this.times = 0;
this.instance = 0;
this.isRecursiveAncestor = isRecursiveAncestor;
tgEngine = engine;
get_max_qtty = (max_qtty == -1);
contents = new Vector();
attributes = new Vector();
containers = new Vector();
varQttyContents = new Vector();
scans = new Vector();
this.randomGenerator = randomGenerator;
this.isLiteral = isLiteral;
this.resetGenes = resetGenes;
}
/**
* returns the number of instances left -- used by the recursive
* descendat to know how many instances to generate.
*/
public int getQttyLeft() {
return times - instance;
}
/**
* determines how many instances of this gene will be produced
*/
public int getQtty() {
int times = min_qtty, max = max_qtty;
if (get_max_qtty) {
int qtty = 0;
for (int k = 0; k < varQttyContents.size(); k++) {
qtty = ((VarQttyGene) varQttyContents.get(k)).getMaxQtty();
if ((max == -1) || (qtty < max)) {
max = qtty;
}
}
if (max < min_qtty) {
throw new ToXgeneErrorException(
"cannot generate minimun quantity of "
+ "\""
+ tagname
+ "\" element.");
}
times = max;
}
if (max_qtty != -1) {
//in this case the template specifies actual min and max qtties
if (min_qtty != max) {
times = (int) randomGenerator.nextInt(max);
}
}
return times;
}
/**
* Generates one single instance of the gene for being added to the given
* list.
*/
public ToxListElement instance(ToxList list) {
int tagNumber = tgEngine.getTagNumber(tagname);
ToxListElement child = new ToxListElement(tagNumber);
if (resetGenes) {
reset();
}
try {
for (int j = 0; j < contents.size(); j++) {
//output all the subelements for this element
((ListGene) contents.get(j)).generate(child);
}
} catch (NoElementsException e) {
throw new ToXgeneErrorException(
"cannot generate more instances of element: " + tagname);
}
return child;
}
/**
* Notifies all scan genes that the output of this gene failed uniqueness
* or where clause constraints.
*/
public void failed() {
int size = scans.size();
if (size > 0) {
for (int i = 0; i < scans.size(); i++) {
((ToxScan) scans.get(i)).rollback();
}
} else {
for (int i = 0; i < contents.size(); i++) {
if (((Gene) contents.get(i)) instanceof ToxElement) {
((ToxElement) contents.get(i)).failed();
}
}
}
}
/**
* Resets the gene.
*/
public void reset() {
for (int i = 0; i < attributes.size(); i++) {
((Gene) attributes.get(i)).reset();
}
for (int i = 0; i < contents.size(); i++) {
((Gene) contents.get(i)).reset();
}
}
/**
* Adds the output of the gene as children of the give ToxListElement.
*/
public void generate(ToxListElement parent) {
if (resetGenes) {
reset();
}
//determines the actual number of occurrences for this element
times = getQtty();
try {
//resets all scan objects
for (int i = 0; i < scans.size(); i++) {
((ToxScan) scans.get(i)).update();
}
for (instance = 0; instance < times; instance++) {
int tagNumber = tgEngine.getTagNumber(tagname);
ToxListElement child = parent.addChild(tagNumber);
//no attributes in lists :)
for (int j = 0; j < contents.size(); j++) {
//output all the subelements for this element
((ListGene) contents.get(j)).generate(child);
}
}
} catch (NoElementsException e) {
throw new ToXgeneErrorException(
"cannot generate more instances of element: " + tagname);
}
}
/**
* Outputs the actual contents of this element into the outStream.
*/
public void generate(PrintStream outStream){
if (resetGenes) {
reset();
}
//determines the actual number of occurrences for this element
times = getQtty();
//resets all scan objects
for (int i = 0; i < scans.size(); i++) {
((ToxScan) scans.get(i)).update();
}
if (isRecursiveAncestor) {
//in this case, we need to keep track of the number of instances.
//and, each time a recursive child is generated, we must count
while (instance < times) {
instance++;
try {
//output the tagname for the object
outStream.print("<" + tagname);
for (int j = 0; j < attributes.size(); j++) {
//ouput all attributes for the element
((Gene) attributes.get(j)).generate(outStream);
}
for (int j = 0; j < containers.size(); j++) {
//ouput all attributes for the element residing in child container
((ContainerGene) containers.get(j)).generateAttributes(
outStream);
}
outStream.print(">"); //done with attributes
for (int j = 0; j < contents.size(); j++) {
//output all the subelements for this element
((Gene) contents.get(j)).generate(outStream);
}
outStream.print("" + tagname + ">");
} catch (NoElementsException e) {
throw new ToXgeneErrorException(
"cannot generate more instances of element: "
+ tagname);
}
if (tgEngine.addNewLines()) {
outStream.print("\n");
}
}
instance = 0;
} else {
//isRecursiveAncestor==false here. then, we go on "memoryless mode"
try {
for (instance = 0; instance < times; instance++) {
//output the tagname for the object
outStream.print("<" + tagname);
for (int j = 0; j < attributes.size(); j++) {
//ouput all attributes for the element
((Gene) attributes.get(j)).generate(outStream);
}
for (int j = 0; j < containers.size(); j++) {
//ouput all attributes for the element residing in child container
((ContainerGene) containers.get(j)).generateAttributes(
outStream);
}
outStream.print(">"); //done with attributes
for (int j = 0; j < contents.size(); j++) {
//output all the subelements for this element
((Gene) contents.get(j)).generate(outStream);
}
outStream.print("" + tagname + ">");
if (tgEngine.addNewLines()) {
outStream.print("\n");
}
}
} catch (NoElementsException e) {
throw new ToXgeneErrorException(
"cannot generate more instances of element: " + tagname);
}
}
}
/**
* Outputs the actual contents of this element into the outStream. This
* version is used only for recursive elements
*/
public void generateRecursive(PrintStream outStream, int depth) {
if (instance < times) {
instance++;
//resets all scan objects
for (int i = 0; i < scans.size(); i++) {
((ToxScan) scans.get(i)).update();
}
try {
outStream.print("<" + tagname);
for (int j = 0; j < attributes.size(); j++) {
//ouput all attributes for the element
((Gene) attributes.get(j)).generate(outStream);
}
for (int j = 0; j < containers.size(); j++) {
//ouput all attributes for the element residing in child container
//no recursive attribute generation yet!!!
((ContainerGene) containers.get(j)).generateAttributes(
outStream);
}
outStream.print(">"); //done with attributes
for (int j = 0; j < contents.size(); j++) {
Gene gene = (Gene) contents.get(j);
if (gene instanceof ToxAlternatives) {
((ToxAlternatives) gene).generateRecursive(
outStream,
depth);
} else {
if (gene instanceof ToxScan) {
((ToxScan) gene).generateRecursive(
outStream,
depth);
} else {
gene.generate(outStream);
}
}
}
} catch (NoElementsException e) {
throw new ToXgeneErrorException(
"cannot generate more instances of element: " + tagname);
}
outStream.print("" + tagname + ">");
}
}
/**
* Outputs the actual contents of this element into the outStream. This
* version is used only for recursive elements
*/
public void generateRecursive(ToxListElement element, int depth) {
if (instance < times) {
instance++;
//resets all scan objects
for (int i = 0; i < scans.size(); i++) {
((ToxScan) scans.get(i)).update();
}
try {
int tagNumber = tgEngine.getTagNumber(tagname);
ToxListElement child = new ToxListElement(tagNumber);
//no attributes in lists :)
for (int j = 0; j < contents.size(); j++) {
//output all the subelements for this element
ListGene gene = (ListGene) contents.get(j);
if (gene instanceof ToxAlternatives) {
((ToxAlternatives) gene).generateRecursive(
child,
depth);
} else {
gene.generate(child);
}
}
} catch (NoElementsException e) {
throw new ToXgeneErrorException(
"cannot generate more instances of element: " + tagname);
}
}
}
public void addAttribute(ToxAttribute attr) {
attributes.add(attr);
}
public void addContent(Gene item) {
contents.add(item);
}
public void addComplexType(ToxComplexType holder) {
attributes.addAll(holder.attributes());
contents.addAll(holder.contents());
containers.addAll(holder.containers());
varQttyContents.addAll(holder.varQttyContents());
scans.addAll(holder.scans());
}
/**
* Adds a new attribute container to this element.
*/
public void addContainer(ContainerGene gene) {
get_max_qtty = true;
containers.add(gene);
}
/**
* Adds a new gene to the contents of the element. This gene has a
* variable number of occurrences, depending on the result of a
* query. This number of occurrences is used to compute the actual number
* of occurrences for this element. The child gene is also added to the
* content list for this element.
*/
public void addVarQttyContent(VarQttyGene gene) {
varQttyContents.add(gene);
contents.add(gene);
}
/**
* Adds a new tox-scan/tox-sample gene to the list of scan genes in this
* element. This gene is also added to the contents vector so that it is
* processed in the correct order.
*/
public void addScan(ToxScan gene) {
scans.add(gene);
addVarQttyContent(gene);
}
/**
* Outputs the tagName for the element. Used for a ToxFile element when
* printing the doctype information.
*/
public String tagName() {
return tagname;
}
public String name() {
return tagname;
}
public Vector children() {
return contents;
}
public Vector getChildren() {
Vector result = null;
for (int i = 0; i < contents.size(); i++) {
ListGene gene = (ListGene) contents.get(i);
if (gene instanceof LiteralGene) {
continue;
}
if (gene instanceof ToxScan
|| gene instanceof ToxAlternatives
|| gene instanceof ToxIf) {
Vector children = gene.getChildren();
if (children != null) {
if (result == null) {
result = new Vector();
}
result.addAll(children);
}
continue;
}
if (result == null) {
result = new Vector();
}
result.add(gene);
}
return result;
}
public Vector getChildrenByName(String name)
throws ToxListElementException {
if (contents.size() == 0) {
throw new ToxListElementException();
}
Vector result = null;
for (int i = 0; i < contents.size(); i++) {
ListGene gene = (ListGene) contents.get(i);
if (gene instanceof LiteralGene) {
continue;
}
if (gene instanceof ToxScan
|| gene instanceof ToxAlternatives
|| gene instanceof ToxIf) {
Vector children = gene.getChildrenByName(name);
if (children != null) {
if (result == null) {
result = new Vector();
}
result.addAll(children);
}
continue;
}
if (name.compareTo(gene.name()) == 0) {
if (result == null) {
result = new Vector();
}
result.add(gene);
}
}
return result;
}
public int numIterators() {
int result = 0;
for (int i = 0; i < contents.size(); i++) {
result += ((Gene) contents.get(i)).numIterators();
}
for (int i = 0; i < attributes.size(); i++) {
result += ((Gene) attributes.get(i)).numIterators();
}
return result;
}
public void destroy() {
try {
for (int i = 0; i < contents.size(); i++) {
((Gene) contents.get(i)).destroy();
}
for (int i = 0; i < attributes.size(); i++) {
((Gene) attributes.get(i)).destroy();
}
contents.clear();
attributes.clear();
containers.clear();
varQttyContents.clear();
scans.clear();
contents = null;
attributes = null;
containers = null;
varQttyContents = null;
scans = null;
} catch (Exception e) {
}
}
/**
* Returns the datatype of instances of this gene.
*/
public String getType() {
int size = contents.size();
String result = null;
for (int i = 0; i < size; i++) {
ListGene gene = (ListGene) contents.get(i);
if (gene instanceof ToxElement) {
return "complex";
}
if (gene instanceof LiteralGene) {
result = reconcile(result, gene.getType());
}
if (gene instanceof ToxScan
|| gene instanceof ToxIf
|| gene instanceof ToxAlternatives) {
Vector children = gene.getChildren();
int size2 = children == null ? 0 : children.size();
for (int j = 0; j < size; j++) {
ListGene child = (ListGene) children.get(j);
if (child instanceof ToxElement) {
return "complex";
} else {
String subtype = child.getType();
result = reconcile(result, subtype);
}
}
}
}
return result;
}
private String reconcile(String t1, String t2) {
if (t1 == null) {
return t2;
}
if (t2 == null) {
return t1;
}
if (t1.compareTo(t2) == 0) {
return t1;
}
if (t1.compareTo("string") == 0 || t2.compareTo("string") == 0) {
return "string";
}
if (t1.compareTo("complex") == 0 || t2.compareTo("complex") == 0) {
return "complex";
}
if ((t1.compareTo("integer") == 0 && t2.compareTo("real") == 0)
|| (t2.compareTo("integer") == 0 && t1.compareTo("real") == 0)) {
return "real";
}
if ((t1.compareTo("integer") == 0 && t2.compareTo("date") == 0)
|| (t2.compareTo("integer") == 0 && t1.compareTo("date") == 0)) {
return "date";
}
return "complex";
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy