toxgene.core.genes.trees.ToxScan Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ToxGene Show documentation
Show all versions of ToxGene Show documentation
Modified ToXGene for the iBench project.
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