All Downloads are FREE. Search and download functionalities are using the official Maven repository.

toxgene.core.genes.trees.ToxElement Maven / Gradle / Ivy

The newest version!
/**
 * 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("");
				} 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("");

					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("");
		}
	}

	/**
	 * 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 - 2024 Weber Informatics LLC | Privacy Policy