
toxgene.core.genes.trees.ToxScan Maven / Gradle / Ivy
/**
* 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 - 2025 Weber Informatics LLC | Privacy Policy