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

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

The newest version!
/**
 * Provides an access method for a ToxList.
 *
 * @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.genes.ContainerGene;
import toxgene.core.genes.CreateGeneException;
import toxgene.core.genes.Gene;
import toxgene.core.genes.VarQttyGene;
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.lists.WhereClause;
import toxgene.core.parser.ToxComplexType;
import toxgene.core.random.ToxRandom;
import toxgene.util.Dictionary;
import toxgene.util.DuplicateKeyException;
import toxgene.util.KeyNotFoundException;

public class ToxScan implements VarQttyGene,TreeGene,ListGene,ContainerGene{
  private final static int SEQUENTIAL = 1;
  private final static int RANDOM = 2;
  private final static int SHUFFLE = 3;

  private final static int MASTER = 1;
  private final static int SLAVE_INDEPENDENT = 2;
  private final static int SLAVE_DEPENDENT = 3;

  private final static int LITERAL = 1;
  private final static int COMPLEX = 2;

  /**
   * Determines whether the vector containing the elements in the iterator
   * has to be repopulated.
   */
  private boolean populated;
  /**
   * Determines whether this iterator gene is a tox-sample.
   */
  private boolean isSample;
  /**
   * Determines whether this iterator gene is a tox-foreach.
   */
  private boolean isForeach;
  /** 
   * Determines whether duplicate entries are allowerd in the output of this
   * iterator gene. Used only for sample iterators.
   */
  private boolean duplicates;
  /**
   * Datatype of the elements in the iterator.
   */
  private int type;
  /**
   * Mode of operation for this iterator:
   *
   * MASTER: the gene has no other iterator genes as its ancestor.
   *
   * SLAVE_DEPENDENT: the gene is a descendant of another iterator and its
   * contents are defined as a query relative to the current element of one
   * of its ancestors.
   *
   * SLAVE_INDEPENDENT: the gene is a descendant of another iterator, but
   * its contents do not depend on any of its ancestors.
   */
  private int mode;
  /**
   * Number of elements in the vector of contents.
   */
  private int size;
  private ToxList list;
  /**
   * Contains the result of the query as a set of ToxListElement objects.
   */
  private Vector elements;
  /**
   * Contains the genes that are declared inside this iterator
   * (tox-scan/tox-sample). These genes are the "content" of this iterator
   * gene and thus are generated whenever it is.
   */
  private Vector genes;
  /**
   * Contains the attributes declared inside this iterator. The ouput of
   * these attribute genes is appended to the element that contains this
   * iterator gene.
   */
  private Vector attributes;
  /**
   * Contains all container genes that are declared inside this iterator.
   */
  private Vector containers;
  /**
   * Contains all queries that are bound to this iterator gene. Such query
   * genes are notified whenever the cursor of the iterator moves.
   */
  private Vector queries;
  /**
   * Current element being scanned.
   */
  private int current;
  /**
   * Query over other scan element, used for slave scans only
   */
  private Query myQuery;
  /**
   * Absolute path expression that corresponds to a query relative to a
   * list. All elements in this iterator are reachable by this path. Used
   * for determining the type of the elements in this iterator and also to
   * get the absolutePaths of its descendant iterators or query genes.
   */
  private String absolutePath;
  /**
   * Name of this iterator gene, provided by the user for later reference in
   * either queries or other iterator genes.
   */
  private String varName;
  /**
   * Master iterator gene for this particular gene. It can be any ancestor
   * iterator gene.
   */
  private ToxScan master;
  /**
   * Contains all named iterator genes that are ancestors of this one. This
   * dictionary is used to find out the correct master iterator and is
   * passed to all descendants of this gene.
   */
  private Dictionary ancestors;
  /**
   * Pseudo-random number generator. Used only for tox-sample iterator genes.
   */
  private ToxRandom rand;
  /**
   * Contains all iterator genes that are slaves of this one (and thus
   * descendants, not necessarily children). These slaves have to be
   * notified whenever this iterator changes its cursor.
   */
  private Vector slaves;
  /**
   * Marks the elements that have been used already. This is used only for
   * sample genes that do not allow repetition.
   */
  private boolean[] usedElements;
  private int lastUsed;
  /**
   * Where clause used to filter which elements of the list are present in
   * the iterator.
   */
  private WhereClause whereClause;
  /**
   * The recursive generation of elements requires the cursor element to be
   * updated *before* generating the children of this cursor. To avoid a big
   * mess, we skip the first cursor update.
   */
  private boolean isFirst;
  /**
   * Attributes are generated *before* the contents of the scan are. So, we
   * need to advance the cursor *before* generating the attributes as
   * well. At content generation time we need to know whether the cursor has
   * been updated already when generating the attributes.
   */
  private boolean notUpdated;
  /**
   * Element node in the DOM tree corresponding to this scan element in the
   * template document. Used for error reporting.
   */
  private int templateNodeLocation;
	/**
	 * tells whether this iterator was copied using a SOFT query. If
	 * this is the case, then the elements in the iterator cannot be
	 * deleted by the the destroy() method.
	 */
	private boolean doQuerySOFT;
	/**
	 * points to the Engine that drives the current session; used to
	 * obtain new random seeds for the ToxUniform distribution that is
	 * created here.
	 */
	private Engine tgEngine;
	

  public ToxScan(String fullPath, ToxScan parent, String varName, 
								 boolean isForeach, boolean isSample, boolean duplicates, 
								 ToxRandom rand, String clause, int nodeLocation,
								 Engine engine){
		//process the path that defines this master scan
		int index;
		String path = "";

		this.varName = varName;
		templateNodeLocation = nodeLocation;
		genes = new Vector(10,10);
		attributes = new Vector(10,10);
		containers = new Vector(10,10);
		queries = new Vector(10,10);
		slaves = new Vector(10,10);
		ancestors = new Dictionary();
		//this makes sure the list will be populated at least once
		populated = false;
		isFirst = true;
		notUpdated = true;
		current = 0;
		doQuerySOFT = false;
		tgEngine = engine;

		//keep track of named ancestors, if any
		if (parent != null){
			ancestors = new Dictionary(parent.ancestors());
			if (parent.varName().length() != 0){
				//we register only named ancestors
				try{
					ancestors.add(parent.varName(), parent);
				}
				catch (DuplicateKeyException e){
					throw new CreateGeneException("variable name: "+master.varName()
																				+" alerady used!");
				}
			}
		}
	
		//check whether this varName is valid
		if (varName.length() != 0 && ancestors != null){
			boolean used = true;
			try{
				ancestors.get(varName);
			}
			catch (KeyNotFoundException e){
				used = false;
			}
			if (used){
				throw new CreateGeneException("in tox-scan: "+fullPath+" variable $"
																			+varName+" alerady used!");
			}
		}

		//process the path
		if (fullPath.charAt(0) != '[' || 
				fullPath.charAt(fullPath.length()-1) !=']'){

			throw new CreateGeneException("invalid path specified for ToxScan: "
																		+fullPath);
		}

		path = fullPath.substring(1,fullPath.length()-1);

		if (parent != null){
			//register this slave scan within its parent. Whenever the parent
			//cursor advances, this scan is refreshed if necessary.
			parent.registerSlave(this);
	  
			//check whether this is scan is bounded to another
			if (path.charAt(0) == '$'){
				//the path expression of this scan is relative to another scan
				//gene, thus it has to be refreshed whenever that one is
				mode = SLAVE_DEPENDENT;
		
				//get the name of the master tox-scan
				index = path.indexOf('/');
				if (index == -1){
					throw new CreateGeneException("invalid cursor definition: a path "+
																					"within master  cursor "
																					+path.substring(1)
																					+" must be specified");
				}
				//get the name of the master scan (which can be different than the
				//parent scan!!!)
				String temp = path.substring(1,index);
		
				try{
					master = (ToxScan) ancestors.get(temp);
					myQuery = new Query("["+path.substring(index+1)+"]", master, null,
															templateNodeLocation,
															tgEngine.getToXgeneReporter());
					master.registerQuery(myQuery);
					absolutePath = master.absolutePath+"/"+myQuery.relativePath();
					this.list = master.list;
		  
					if (clause.length() != 0){
						whereClause = new WhereClause(clause, master,templateNodeLocation,
																					tgEngine.getToXgeneReporter(),
																					tgEngine.simpleTypes());
					}
				}
				catch (KeyNotFoundException e){
					throw new CreateGeneException("cannot find master cursor \""+temp+
																					"\" used in "+fullPath);
				}
			}
			else{
				//the path expression is not bound to any other scan operator
				mode = SLAVE_INDEPENDENT;
				absolutePath = path;
		
				//get the name of the list which is being scanned
				String listName = "";
				int offset = 0;
				index = path.indexOf('/');
				if (index == -1){
					listName = path;
					offset = path.length();
				}
				else{
					listName = path.substring(0, index);
					offset = index+1;
				}
		
				try{
					list = tgEngine.getToxList(listName);
				}
				catch (KeyNotFoundException e){
					throw new CreateGeneException("cannot find list: "+listName
																				+" for tox-scan");
				}
		
				myQuery = new Query("["+path.substring(offset)+"]", list, null,
														templateNodeLocation,
														tgEngine.getToXgeneReporter());
		
				if (clause.length() != 0){
					if (clause.indexOf("$") != -1){
						//this means that the where clause is in fact a join
						whereClause = new WhereClause(clause, list, parent,
																					path.substring(offset),
																					tgEngine.getToXgeneReporter(),
																					tgEngine.simpleTypes());
						
						mode = SLAVE_DEPENDENT;
					}
					else{
						//this means the where clause is a simple condition on the iterator
						whereClause = new WhereClause(clause, list,path.substring(offset),
																					tgEngine.getToXgeneReporter(),
																					tgEngine.simpleTypes());
					}
				}
			}
		}
		else{
			mode = MASTER; //this is an independent tox-scan
			absolutePath = path;
	  
			//get the name of the list which is being scanned
			String listName = "";
			int offset = 0;
			index = path.indexOf('/');
			if (index == -1){
				listName = path;
				offset = path.length();
			}
			else{
				listName = path.substring(0, index);
				offset = index+1;
			}
	  
			try{
				list = tgEngine.getToxList(listName);
			}
			catch (KeyNotFoundException e){
				throw new CreateGeneException("cannot find list: "+listName
																			+" for tox-scan");
			}
	  
			myQuery = new Query("["+path.substring(offset)+"]", list, null,
													templateNodeLocation,tgEngine.getToXgeneReporter());
	  
			if (clause.length() != 0){
				whereClause = new WhereClause(clause, list, path.substring(offset),
																			tgEngine.getToXgeneReporter(),
																			tgEngine.simpleTypes());
			}
		}
	
		//determines the type of the nodes that are being scanned
		if(myQuery.expressionType() == Expression.COMPLEX){
			type = COMPLEX;
		}
		else{
			type = LITERAL;
		}

		this.isSample = isSample;
		if (isSample){
			this.duplicates = duplicates;
			this.rand = rand;
		}

		this.isForeach = isForeach;
		doQuerySOFT = ((whereClause == null) && !(isSample && !duplicates));
  }

  public Dictionary ancestors(){
		return ancestors;
  }

  public String varName(){
		return varName;
  }

  public String absolutePath(){
		return absolutePath;
  }

  public String name(){
		return "tox-scan";
  }

  /**
   * Returns all genes in this iterator, whithout skipping iterators,
   * alternatives and ifs. Used to find references to lists.
   */
  public Vector children(){
		return genes;
  }

  public Vector getChildren(){
		if (genes.size() == 0){
			throw new ToxListElementException();
		}
		Vector result = null;

		for (int i=0; i 0);
  }

  public void generateAttributes(PrintStream outStream){
		if (hasAttributes()){
			if (!populated){
				populate();
			}
	  
			//we update the cursor *before* generating the contents, so the
			//recursive generation works
			if (isFirst){
				isFirst = false;//but not the first time
			}
			else{
				next();
			}
			//this prevents the cursor to be updated again when generating the
			//contents.
			notUpdated = false;

			for (int i=0; i 0){
				current--;
			}
		}
  }

  public int getMaxQtty(){
		if (!populated){
			populate();
		}

		// in this case we could go on forever
		if (isSample && duplicates){
			return -1;
		}

		if (isForeach){
			return (elements == null? 0 : 1);
		}

		return (size-current);
  }

  private void registerSlave(ToxScan slave){
		slaves.add(slave);
  }

  private void next(){
		if (isSample){
			if(duplicates){
				//picks another element at random
				current = (int) rand.nextInt();
			}
			else{
				//remove the used elementand pick another

				lastUsed = current;//we need this in case the tox-scan is rolled back
				usedElements[lastUsed] = true;
				current = (int) rand.nextInt();
				if (usedElements[current]){
					//here we have to find the closest unused element in the vector
					int next = current  1 ? current-- : 0;

					//find the closest unused element in the vector
					while (next0 && usedElements[previous]){
						previous--;
					}

					if (usedElements[next]){
						current = previous;
					}
					else{
						if (usedElements[previous]){
							current = next;
						}
						else{
							if ((current - previous) < (next - current)){
								current = previous;
							}
							else{
								current = next;
							}
						}
					}
				}
			}
		}
		else{
			//simply advances the pointer
			current += 1;
		}
  }

	/**
	 * returns the number of iterators that require a buffer for
	 * building queries. This method is only used when a persistent
	 * object manager is activated.
	 */
	public int numIterators(){
		int result;
		
		if (doQuerySOFT){
			result = 0;
		}
		else{
			result = 1;
		}
		
		for (int i=0; i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy