Package at.ofai.gate.japeutils.ops

Source Code of at.ofai.gate.japeutils.ops.ValueRef

/*
*  ValueRef.java
*
*  $Id: ValueRef.java 37 2012-04-16 13:33:35Z johann.petrak@gmail.com $
*/

package at.ofai.gate.japeutils.ops;

import gate.Annotation;
import gate.AnnotationSet;
import gate.FeatureMap;
import gate.util.GateRuntimeException;
import gate.jape.constraint.*;
import gate.jape.*;
import java.util.Map;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;


/**
* A ConstraintPredicate that makes it possible to use value back-references
* in JAPE rules.
* <p>
* The ConstraintPredicate "valueref" must be used with one of the following
* operators:
* <ul>
* <li>!=~ This operator should be used once in its own phase to reset
* the data structures between documents
* <li>!~ This operator should be used as the first operator in a  sequence
* where identical values should be matched and will initialize a reference
* with the value.
* <li>== This operator should be used in all subsequent locations where the
* value that has been assigned to a reference already should be matched.
* </ul>
* <p>
* Here is an example for a phase to initialize the datastructures. Note that
* the reference does not matter and only one reference name needs to be used,
* even if the rest of the phases uses several different reference names.
* <pre>
* Phase: reset
* Input: Token
* Options: control = once
* Rule: reset1
* ({Token valueref {Token.string !=~ "ref"}}) --> {}
* </pre>
* <p>
* <p>
* Here is an example for a rule that makes shure that three tokens with the
* same values for feature pos occur after one another:
* <pre>
* ({Token valueref {Token.pos !~ "ref"}}
*  {Token valueref {Token.pos == "ref"}}
*  {Token valueref {Token.pos == "ref"}}):label
* -->:label.ThreeTimes = {}
* </pre>
* @author Johann Petrak
*/
public class ValueRef implements ConstraintPredicate {
 
  private static final long serialVersionUID = -2369138804874616879L;
  protected AnnotationAccessor accessor;
  protected Object value;
 
  static Map<String, Set<Object>> valueRefsCur =
    new HashMap<String,Set<Object>>();
  static Map<String, Set<Object>> valueRefsLast =
    new HashMap<String,Set<Object>>();
  static Map<String, Integer> curOffsets =
    new HashMap<String, Integer>();
 
  protected String referenceName = "";
  protected String featureName = "";
  private static final int OPERATOR_EQUALS = 1;
  private static final int OPERATOR_NOTEQUALS = 2;
  private static final int OPERATOR_RESET = 0;
  private static final int OPERATOR_GREATER=3;
  private static final int OPERATOR_GREATEREQUALS=4;
  private static final int OPERATOR_LESS=5;
  private static final int OPERATOR_LESSEQUALS=6;
  private static final int OPERATOR_CLEAR=7;
 
  protected int operator = OPERATOR_EQUALS;
 
  public ValueRef() {
    //System.out.println("MyConstraint: default constructor ");   
  }
  public ValueRef(AnnotationAccessor accessor, Object value) {
    // TODO: when is this ever called?
    //System.out.println("MyConstraint: two args constructor "+accessor+"/"+value);
  }

  public boolean matches(Annotation annot, AnnotationSet context)
    throws GateRuntimeException
  {
    // The clear operator is used in a phase to make sure everything is
    // reset between document and phases
    if(operator == OPERATOR_CLEAR) {
      curOffsets.clear();
      valueRefsCur.clear();
      valueRefsLast.clear();
      //System.out.println("Clearing for="+referenceName);
      return true;
    }
   
    Object featureValue = getFeature(annot.getFeatures(),featureName);
    int offset = annot.getStartNode().getOffset().intValue();
    Integer curOffset = curOffsets.get(referenceName);
    if(curOffset == null) {
      curOffset = -1;
    }
    //System.out.println("curoffset="+curOffset+" offset="+offset);
   
    // if we get a reset operator, what we do depends on the offset:
    // if it is the same offset as last time, we obviously have another
    // annotation of the target type at the same offset and we add its value
    // to the current set of values. If the offset is different, we need to
    // start a new cycle and we delete the old sets for this referenceName
    // and create a new current set for it.
    if(operator == OPERATOR_RESET) {
      if(curOffset == offset) {
        //System.out.println("Reset/add: referenceName="+referenceName+", feature="+featureName+", offset="+offset+", val="+featureValue);
        valueRefsCur.get(referenceName).add(featureValue);
      } else {
        //System.out.println("Reset/new: referenceName="+referenceName+", feature="+featureName+", offset="+offset+", val="+featureValue);
        curOffsets.put(referenceName,offset);
        Set<Object> newset = new HashSet<Object>();
        newset.add(featureValue);
        valueRefsCur.put(referenceName, newset);
        valueRefsLast.remove(referenceName);
      }
      return true;
    }
   
    // Everything else is a comparison with values set earlier. If we make
    // a comparison at a location where we made a comparison earlier,
    // just check if the current value matches the last valueRefs and add it
    // to the current set if yes and return true.
    // If we have a new offset, the current valueRefs become the lastRefs and
    // a new current valueRefs set is created.
    if(curOffset != offset) {
      curOffsets.put(referenceName,offset);
      //System.out.println("Compare/new: referenceName="+referenceName+", feature="+featureName+", offset="+offset+", val="+featureValue);
      valueRefsLast.put(referenceName, valueRefsCur.get(referenceName));
      valueRefsCur.put(referenceName, new HashSet<Object>());
    }
    // Comparisons are all made by comparing the current value to all values
    // in the last set. If a match is found the value is added to the curset
    // and true is returned, otherwise we just return false.
    if(operator == OPERATOR_EQUALS) {     
      boolean ret = equal(valueRefsLast.get(referenceName),featureValue);
      //System.out.println("Compare/equal: referenceName="+referenceName+", feature="+featureName+", offset="+offset+", val="+featureValue+" ret="+ret);
      if(ret) {
        valueRefsCur.get(referenceName).add(featureValue);
      }
      return ret;
    } else {
      // this should never occur as we check and set the operator in setValue
      throw new GateRuntimeException("Operator not (yet) supported");
    }
  }
  public void setAccessor(AnnotationAccessor accessor) {
    this.accessor = accessor;
    //System.out.println("MyConstraint: setAccessor "+accessor);
  }
  public AnnotationAccessor getAccessor() {
    //System.out.println("MyConstraint: getAccessor");
    return this.accessor;
  }
  public void setValue(Object value) {
    this.value = value;
    //System.out.println("setValue for "+value);
    if(!(value instanceof Constraint)) {
      throw new GateRuntimeException("Not a constraint: "+value);
    }
    Constraint constraint = (Constraint)value;
    if(constraint.isNegated()) {
      throw new GateRuntimeException("Constraint must not be negated: "+constraint);
    }
    if(constraint.getAttributeSeq().size() != 1) {
      throw new GateRuntimeException("Constraint must have one predicate: "+constraint);
    }
    String annType = constraint.getAnnotType();
    //System.out.println("Annotation type is "+annType);
    ConstraintPredicate pred = constraint.getAttributeSeq().get(0);
    String op = pred.getOperator();
    //System.out.println("Operator is "+op);
    if(op.equals("!~")) {
      operator = OPERATOR_RESET;
    } else if(op.equals("!=~")) {
      operator = OPERATOR_CLEAR;
    } else if(op.equals("==")) {
      operator = OPERATOR_EQUALS;
    } else {
      //System.err.println("Operator is "+op+" but must be one of !=~ (reset), ==, or !=");
      throw new GateRuntimeException("Constraint operator must be !~ (reset),  !=~ (clear), or == (equal to ref)");
    }
    //System.out.println("setValue op is "+op);
    Object predObj = pred.getValue();
    //if(!(predObj instanceof String)) {
    //  throw new GateRuntimeException("Value of predicate must be a string: "+predObj+" not a "+predObj.getClass());
    //}
    // String predValue = (String)predObj;
    String predValue = predObj.toString();
    //System.out.println("setValue pred value is "+predValue);
   
    //System.out.println("Value is "+predValue);
    referenceName = predValue;
    AnnotationAccessor aa = pred.getAccessor();
    String key = aa.getKey().toString();
    //System.out.println("setValue key is "+key);
    featureName = key;
    //System.out.println("Initialized constraint: ref="+referenceName+", feature="+featureName);
  }
  public Object getValue() {
    //System.out.println("MyConstraint: getValue: "+this.value);
    return this.value;
  }
  public String getOperator() {
    //System.out.println("MyConstraing: getOperator: "+"valueref");
    return "valueref";
  }
 
  // returns true if the object b is equal to one of the objects in the set
  protected boolean equal(Set<Object> set, Object b) {
    if(b == null) { return false; }
    for(Object a : set) {
      if (a.equals(b)) { return true; }
    }
    return false;
  }
 
  // returns a.compareTo(b) if both are of the same class and Comparable
  // otherwise throws an exception.
  protected int compare(Object a, Object b) {
    if(a != null && b != null) {
      if(a.getClass().equals(b.getClass())) {
        if(a instanceof Comparable) {
          return ((Comparable)a).compareTo((Comparable)b);
        } else {
          throw new GateRuntimeException(
            "less than or equal comparison but not both are comparable: a="
            +a+",b="+b);
        }
      } else {
          throw new GateRuntimeException(
            "less than or equal comparison but not both of the same class: a="
            +a+",b="+b);
      }
    } else {
          throw new GateRuntimeException(
            "less than or equal comparison but not both different from null: a="
            +a+",b="+b);
    }
  }
 
  private Object getFeature(FeatureMap fm, String name) {
    Object ret = fm.get(name);
    if(ret == null) {
      warnOnce("Null value in valueRef for feature "+name);
    }
    return ret;
  }
 
  private void warnOnce(String message) {
    if(!alreadyWarned.contains(message)) {
      alreadyWarned.add(message);
      System.out.println(message);
    }
  }
 
  private Set<String> alreadyWarned = new HashSet<String>();
 
}
TOP

Related Classes of at.ofai.gate.japeutils.ops.ValueRef

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.