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

eu.mihosoft.vmf.vmftext.grammar.impl.CustomRuleImpl Maven / Gradle / Ivy

The newest version!

package eu.mihosoft.vmf.vmftext.grammar.impl;

// vmf imports
//import eu.mihosoft.vmf.runtime.core.*;
//import eu.mihosoft.vmf.runtime.core.internal.*;
import eu.mihosoft.vcollections.*;
import eu.mihosoft.vmf.vmftext.grammar.*;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyChangeListener;
import java.util.Objects;
import java.util.Arrays;

// property types imports

// implementation

/**
 * An implementation of the model object {@code eu.mihosoft.vmf.vmftext.grammar.CustomRule}.
 */
@SuppressWarnings("deprecation")
class CustomRuleImpl implements CustomRule, eu.mihosoft.vmf.runtime.core.internal.VObjectInternalModifiable, VCloneableInternal {

  // --------------------------------------------------------------------
  // --- declaration of member variables
  // --------------------------------------------------------------------


  /*package private*/ eu.mihosoft.vmf.vmftext.grammar.GrammarModel model;
  /*package private*/ java.lang.String text;


// --------------------------------------------------------------------
// --- declaration of delegation variables
// --------------------------------------------------------------------


  private PropertyChangeSupport propertyChanges;

  // referenced by
  private final VList referencedBy = VList.newInstance(new java.util.ArrayList<>());
  // references
  private final VList references = VList.newInstance(new java.util.ArrayList<>());

  // --------------------------------------------------------------------
  // --- public constructors
  // --------------------------------------------------------------------

  public CustomRuleImpl() {

// --------------------------------------------------------------------
// --- declaration of delegation methods
// --------------------------------------------------------------------


// --------------------------------------------------------------------
// --- initialization of default values
// --------------------------------------------------------------------
    // property 0
    // -> no default value is present
    // property 1
    // -> no default value is present

  }

  // --------------------------------------------------------------------
  // --- public getter methods for accessing properties
  // --------------------------------------------------------------------


  @Override
  public eu.mihosoft.vmf.vmftext.grammar.GrammarModel getModel() {
    return this.model;

  } // end of eu.mihosoft.vmf.vmftext.grammar.GrammarModel getModel()
  @Override
  public java.lang.String getText() {
    return this.text;

  } // end of java.lang.String getText()

  // --------------------------------------------------------------------
  // --- public setter methods for setting properties
  // --------------------------------------------------------------------


    @Override
  public void setModel(eu.mihosoft.vmf.vmftext.grammar.GrammarModel model) {

    // opposite is a collection type. we just need to add this to the
    // opposite collection which will handle the containment just fine

    // nothing to do, values are identical
    if(this.model == model) {
      return;
    }

    // remove this from previous opposite
    if(this.model!=null) {
        this.model.getCustomRules().remove(this);
    }

    // add this to new opposite
    if(model!=null) {
        model.getCustomRules().add(this);
    }
  }
    @Override
   public void setText(java.lang.String text) {

    // return early if identical value has been set
    if (this.text == text) {
      return;
    }

    // set the new value
    java.lang.String oldValue = this.text;
    this.text = text;

    // fire property change event
    _vmf_firePropertyChangeIfListenersArePresent("text", oldValue, this.text);
 

  } // setterDeclaration (setter method)
   
  // --------------------------------------------------------------------
  // --- Object methods (equals(), toString() etc.)
  // --------------------------------------------------------------------


  // --------------------------- BEGIN TO_STRING -----------------------------
  @Override
  public String toString() {

    boolean entry = _vmf_getThreadLocalToString().get().isEmpty();
    try {
        // test if "this" has been seen before
        // implementation based on http://stackoverflow.com/a/11300376/1493549
        boolean isImmutable = (this instanceof eu.mihosoft.vmf.runtime.core.Immutable);
        if (!isImmutable && _vmf_getThreadLocalToString().get().containsKey(this)) {
          return "{skipping recursion}";
        } else {
          if(!isImmutable) {
            _vmf_getThreadLocalToString().get().put(this, null);
          }
          entry = true;
        }
        return "{\"@type\":\"CustomRule\"" +
         ", \"text\": \"" + this.text + "\"" +
           "}";
    } finally {
        if (entry) {
            _vmf_getThreadLocalToString().get().clear();
            _vmf_fToStringChecker = null;
        }
    }
  }

  private ThreadLocal> _vmf_getThreadLocalToString() {
    if (_vmf_fToStringChecker==null) {
      _vmf_fToStringChecker = ThreadLocal.withInitial(
        () -> new java.util.IdentityHashMap<>());
    }

    return _vmf_fToStringChecker;
  }

  private ThreadLocal> _vmf_fToStringChecker;

  // end toString()
  // ---------------------------- END TO_STRING ------------------------------


  // --------------------------- BEGIN EQUALITY -----------------------------
  @Override
  public boolean equals(Object o) {

    boolean entry = _vmf_getThreadLocalEquals().get().isEmpty();
    try {
      // test if the object pair (this,o) has been checked before
      boolean isImmutable = (o instanceof eu.mihosoft.vmf.runtime.core.Immutable);
      if (!isImmutable && _vmf_getThreadLocalEquals().get().containsKey(new EqualsPair(this, o))) {
        // This pair has been seen before. That's why we return true now.
        // If this pair wasn't equal, we wouldn't need to do a second
        // comparison. Returning 'true' is equivalent to ignoring this
        // particular test in the calling 'equals()' method.
        return true;
      } else {
        if(!isImmutable) {
          _vmf_getThreadLocalEquals().get().put(new EqualsPair(this, o), null);
        }
        entry = true;
      }

      if (o==null) return false;
      else if (this==o) return true;

      // if object is read-only wrapper then unwrap the actual object
      if(o instanceof ReadOnlyCustomRuleImpl) {
        o = ((ReadOnlyCustomRuleImpl)o)._vmf_getMutableObject();
      }

      // -- try our interface/implementation --

      // perform the actual comparison for each property
      if (o instanceof CustomRuleImpl) {
        CustomRuleImpl other = (CustomRuleImpl) o;
        return           _vmf_equals(this.text, other.text);
      }

      // -- try every implementation that implements our interface --

      // no implementation matched. we end the comparison.
      return false;
    } finally {
      if (entry) {
          _vmf_getThreadLocalEquals().get().clear();
          _vmf_fEqualsChecker = null;
      }
    }
  } // end equals()

  private static boolean _vmf_equals(Object o1, Object o2) {
    boolean oneAndOnlyOneIsNull = (o1 == null) != (o2 == null);
    boolean collectionType = o1 instanceof VList || o2 instanceof VList;

    // since we support lazy initialization for collections,
    // uninitialized empty collection values are defined as equal to null
    // otherwise we would have to initialize these values, which would then
    // neutralize or even negate the positive effect of lazy initialization
    if(oneAndOnlyOneIsNull && collectionType) {
      if(o1==null) {
        return ((VList)o2).isEmpty();
      } else {
        return ((VList)o1).isEmpty();
      }
    } else {
      return Objects.equals(o1,o2);
    }
  }

  @Override
  public int hashCode() {
      boolean entry = _vmf_getThreadLocalHashCode().get().isEmpty();
      try {
          // test if "this class" has been seen before
          //
          // WARNING we use `System.identityHashCode(this)` to prevent recursive
          // hashCode() calls before we do the actual test. This would eliminate
          // the effect of the thread-local map
          if (_vmf_getThreadLocalHashCode().get().containsKey(System.identityHashCode(this))) {
            return 0; // already visited
          } else {
            _vmf_getThreadLocalHashCode().get().put(System.identityHashCode(this), null);
            int value = _vmf_deepHashCode(
            this.text        );
            entry = true;
            return value;
          }

      } finally {
          if (entry) {
              _vmf_getThreadLocalHashCode().get().clear();
              _vmf_fHashCodeChecker = null;
          }
      }

  } // end hashCode()

  // fixes 'array discovery problems' with the 'Objects.hash(...)' method
  // see http://stackoverflow.com/questions/30385018/how-to-use-java-7-objects-hash-with-arrays
  private int _vmf_deepHashCode(Object... fields) {
      // WARNING we are not allowed to pass arrays that contain itself
      //         or are contained in nested arrays
      return Arrays.deepHashCode(fields);
  } // end _vmf_deepHashCode()

  /**
   * The purpose of this class is to store a pair of objects used for equals().
   * This class's equals() method checks equality by object identity. Same
   * for hashCode() which uses identity hashes of 'first' and 'second' to
   * compute the hash.
   *
   * This class can be used in conjunction with a regular HashMap to get
   * similar results to an IdentityHashMap, except that in this case identity
   * pairs can be used. And we don't have to use a map implementation that is
   * deliberately broken by design.
   */
  private static class EqualsPair {

      final Object first;
      final Object second;

      public EqualsPair(Object first, Object second) {
          this.first = first;
          this.second = second;
      }

      @Override
      public int hashCode() {
          return Objects.hash(System.identityHashCode(first),
                  System.identityHashCode(second));
      }

      @Override
      public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final EqualsPair other = (EqualsPair) obj;
        if (this.first!=other.first) {
            return false;
        }
        if (this.second!=other.second) {
            return false;
        }
        return true;
      }
  }

  private ThreadLocal> _vmf_getThreadLocalEquals() {
    if (_vmf_fEqualsChecker==null) {
      _vmf_fEqualsChecker = ThreadLocal.withInitial(
        () -> new java.util.HashMap<>());
    }

    return _vmf_fEqualsChecker;
  }

  private ThreadLocal> _vmf_getThreadLocalHashCode() {
    if (_vmf_fHashCodeChecker==null) {
      _vmf_fHashCodeChecker = ThreadLocal.withInitial(
        () -> new java.util.HashMap<>());
    }

    return _vmf_fHashCodeChecker;
  }

  private ThreadLocal> _vmf_fEqualsChecker;


  private ThreadLocal> _vmf_fHashCodeChecker;
  // ---------------------------- END EQUALITY ------------------------------


  // --------------------------- BEGIN CLONING -----------------------------
  /**
   * Package private copy constructor.
   * It creates a deep or shallow copy of the specified other object.
   * @param other other object
   * @param deepCopy defines whether to perform a deep copy
   */
  CustomRuleImpl (
    CustomRuleImpl other,
    boolean deepCopy, java.util.IdentityHashMap identityMap
  ) {
    identityMap.put(other,this);

         // property type is an external type (TODO implement cloning strategy)
      this.setText(other.text);
    
   } // end copy constructor

   @Override
   public CustomRuleImpl _vmf_deepCopy(java.util.IdentityHashMap identityMap) {
      if(identityMap.containsKey(this)) {
        return (CustomRuleImpl)identityMap.get(this);
      } else {
        CustomRuleImpl clonedVal = new CustomRuleImpl(this, true, identityMap);
        return clonedVal;
      }
   }

   @Override
   public CustomRuleImpl _vmf_shallowCopy(java.util.IdentityHashMap identityMap) {
      if(identityMap.containsKey(this)) {
        return (CustomRuleImpl)identityMap.get(this);
      } else {
        CustomRuleImpl clonedVal = new CustomRuleImpl(this, false, identityMap);
        return clonedVal;
      }
   }
  @Override
  public CustomRuleImpl clone() /*throws CloneNotSupportedException*/ {
    // http://stackoverflow.com/questions/12886036/deep-copying-a-graph-structure
    // http://softwareengineering.stackexchange.com/questions/228848/how-does-java-handle-cyclic-data-references-when-serializing-an-object
    // https://gist.github.com/kanrourou/47223bdaf481505d4c7e
    // http://www.programcreek.com/2012/12/leetcode-clone-graph-java/
    java.util.IdentityHashMap identityMap =
      new java.util.IdentityHashMap<>();
    return _vmf_deepCopy(identityMap);
  }
  // ---------------------------- END CLONING ------------------------------


// --------------------------------------------------------------------
// --- Builder methods
// --------------------------------------------------------------------

public static class BuilderImpl implements CustomRule.Builder {

  private eu.mihosoft.vmf.vmftext.grammar.GrammarModel model;
  private java.lang.String text;

  private boolean appendCollections = true;

  public BuilderImpl() {}

    public CustomRule.Builder withText(java.lang.String text) {
      this.text = text;
      return this;
    }

  public Builder appendCollections(boolean value) {
    this.appendCollections = value;
    return this;
  }

  public CustomRule build() {
    CustomRuleImpl result = new CustomRuleImpl();
    result.model = this.model;
    // PROP: model
        
      if(result.model!=null && result!=null) {
        ((eu.mihosoft.vmf.runtime.core.internal.VObjectInternal)result)._vmf_references().add(result.model);
        ((eu.mihosoft.vmf.runtime.core.internal.VObjectInternal)result.model)._vmf_referencedBy().add(result);
      }

    result.text = this.text;
    return result;
  }

  public Builder applyFrom(CustomRule o) {
      this.model = o.getModel();
      this.text = o.getText();

    return this;
  }
  public Builder applyTo(CustomRule o) {

      o.setText(text);

    return this;
  }
} // end class BuilderImpl


// --------------------------------------------------------------------
// --- declaration of delegation methods
// --------------------------------------------------------------------


  // --------------------------------------------------------------------
  // --- Utility methods
  // --------------------------------------------------------------------

  @Override
  public void addPropertyChangeListener(PropertyChangeListener l) {
      _vmf_getPropertyChanges().addPropertyChangeListener(l);
  }
  @Override
  public void removePropertyChangeListener(PropertyChangeListener l) {
      _vmf_getPropertyChanges().removePropertyChangeListener(l);

      if(_vmf_getPropertyChanges().getPropertyChangeListeners().length==0) {
          propertyChanges = null;
      }
  }

  private PropertyChangeSupport _vmf_getPropertyChanges() {

      if(propertyChanges==null) {
          propertyChanges = new PropertyChangeSupport(this);
      }

      return propertyChanges;
  }

  private boolean _vmf_hasListeners() {
      return propertyChanges!=null;
  }

  private void _vmf_firePropertyChangeIfListenersArePresent(
    String propertyName, Object oldValue, Object newValue) {
      if(_vmf_hasListeners()) {
          _vmf_getPropertyChanges().
                  firePropertyChange(propertyName, oldValue, newValue);
      }
  }

  // --------------------------------------------------------------------
  // --- Public VMF API
  // --------------------------------------------------------------------

 private eu.mihosoft.vmf.runtime.core.VMF vmf;

  @Override
  public eu.mihosoft.vmf.runtime.core.VMF vmf() {
    if(vmf==null) {
      vmf = new eu.mihosoft.vmf.runtime.core.VMF() {
        public eu.mihosoft.vmf.runtime.core.Content content() {
          return new eu.mihosoft.vmf.runtime.core.Content() {
            public eu.mihosoft.vmf.runtime.core.VIterator iterator() {
              return eu.mihosoft.vmf.runtime.core.VIterator.of(CustomRuleImpl.this);
            }
            public java.util.stream.Stream stream() {
              return eu.mihosoft.vmf.runtime.core.VIterator.of(CustomRuleImpl.this).asStream();
            }

            public eu.mihosoft.vmf.runtime.core.VIterator iterator(eu.mihosoft.vmf.runtime.core.VIterator.IterationStrategy strategy) {
              return eu.mihosoft.vmf.runtime.core.VIterator.of(CustomRuleImpl.this, strategy);
            }
            public java.util.stream.Stream stream(eu.mihosoft.vmf.runtime.core.VIterator.IterationStrategy strategy) {
              return eu.mihosoft.vmf.runtime.core.VIterator.of(CustomRuleImpl.this, strategy).asStream();
            }
            public  java.util.stream.Stream stream(Class type) {
              return stream().filter(e->type.isAssignableFrom(e.getClass())).map(e->(T)e);
            }
            public  java.util.stream.Stream stream(Class type, eu.mihosoft.vmf.runtime.core.VIterator.IterationStrategy strategy) {
              return stream(strategy).filter(e->type.isAssignableFrom(e.getClass())).map(e->(T)e);
            }
            public VList referencedBy() {
              return _vmf_referencedBy().asUnmodifiable();
            }
            public VList references() {
              return _vmf_references().asUnmodifiable();
            }


            @Override
            public CustomRule deepCopy() {
               java.util.IdentityHashMap identityMap =
               new java.util.IdentityHashMap<>();
               return _vmf_deepCopy(identityMap);
            }

            @Override
            public CustomRule shallowCopy() {
              return CustomRuleImpl.
                this._vmf_shallowCopy(new java.util.IdentityHashMap<>());
              }
            };
          }

          private eu.mihosoft.vmf.runtime.core.internal.ChangesImpl changes;

          public eu.mihosoft.vmf.runtime.core.Changes changes() {
            if (changes==null) {
              changes = new eu.mihosoft.vmf.runtime.core.internal.ChangesImpl();
              changes.setModel(CustomRuleImpl.this);
            }

            return changes;
          }

          private eu.mihosoft.vmf.runtime.core.internal.ReflectImpl reflect;

          public eu.mihosoft.vmf.runtime.core.Reflect reflect() {
            if (reflect==null) {
              reflect = new eu.mihosoft.vmf.runtime.core.internal.ReflectImpl();
              reflect.setModel(CustomRuleImpl.this);
            }

            return reflect;
          }


        }; // end vmf
      } // end if null

      return vmf;
  }

  private ReadOnlyCustomRule readOnlyInstance;

  @Override
  public ReadOnlyCustomRule asReadOnly() {

    if(readOnlyInstance==null) {
      readOnlyInstance = new eu.mihosoft.vmf.vmftext.grammar.impl.
        ReadOnlyCustomRuleImpl(this);
    }

    return readOnlyInstance;
  }

  // --------------------------------------------------------------------
  // --- Reflection methods
  // --------------------------------------------------------------------

  // type id for improved reflection performance
  public static final int _VMF_TYPE_ID = 10;

  @Override
  public int _vmf_getTypeId() {
    return _VMF_TYPE_ID;
  }


  static final String[] _VMF_PROPERTY_NAMES = {
    "model",
    "text"
  };

  static final String[] _VMF_PROPERTY_TYPE_NAMES = {
    "eu.mihosoft.vmf.vmftext.grammar.GrammarModel", // type id 14
    "java.lang.String"  // type id -1
  };

  static final int[] _VMF_PROPERTY_TYPES = {
       14, // type eu.mihosoft.vmf.vmftext.grammar.GrammarModel
       -1  // type java.lang.String
  };


  /**
   * - indices of model objects as properties
   * - parents, i.e., containers are skipped
   * - only indices of reference properties and contained elements, i.e.,
   *   children are listed here
   */
  static final int[] _VMF_PROPERTIES_WITH_MODEL_TYPES_INDICES = {
  };

  /**
   * - indices of lists that contain model objects as elements
   */
  static final int[] _VMF_PROPERTIES_WITH_MODEL_ELEMENT_TYPES_INDICES = {
  };

  /**
   * - indices of model objects as properties and model objects as
   *   elements of lists
   * - parents, i.e., containers are skipped
   * - only indices of reference properties and contained elements, i.e.,
   *   children are listed here
   */
  static final int[] _VMF_PROPERTIES_WITH_MODEL_TYPE_OR_ELEMENT_TYPES_INDICES = {
  };

  /**
   * - indices of model children
   * - parents, i.e., containers and pure references are skipped
   * - only indices of contained elements, i.e.,
   *   children are listed here
   */
  static final int[] _VMF_CHILDREN_INDICES = {
  };

  @Override
  public String[] _vmf_getPropertyNames() {
    return _VMF_PROPERTY_NAMES;
  }

  @Override
  public int[] _vmf_getPropertyTypes() {
    return _VMF_PROPERTY_TYPES;
  }

  @Override
  public String[] _vmf_getPropertyTypeNames() {
    return _VMF_PROPERTY_TYPE_NAMES;
  }

  @Override
  public int[] _vmf_getIndicesOfPropertiesWithModelTypes() {
    return _VMF_PROPERTIES_WITH_MODEL_TYPES_INDICES;
  }

  @Override
  public int[] _vmf_getIndicesOfPropertiesWithModelElementTypes() {
    return _VMF_PROPERTIES_WITH_MODEL_ELEMENT_TYPES_INDICES;
  }

  @Override
  public int[] _vmf_getIndicesOfPropertiesWithModelTypeOrElementTypes() {
    return _VMF_PROPERTIES_WITH_MODEL_TYPE_OR_ELEMENT_TYPES_INDICES;
  }

  @Override
  public int[] _vmf_getChildrenIndices() {
    return _VMF_CHILDREN_INDICES;
  }

  @Override
  public Object _vmf_getPropertyValueById(int propertyId) {

    switch(propertyId) {
      case 0:
        // TODO check whether we can prevent lazy initialized properties from
        //      being initialized just for iterating the object graph
        return getModel();
      case 1:
        // TODO check whether we can prevent lazy initialized properties from
        //      being initialized just for iterating the object graph
        return getText();
    }

    return null;
  }

  @Override
  public int _vmf_getPropertyIdByName(String propertyName) {
    switch(propertyName) {
      case "model":
        return 0;
      case "text":
        return 1;
      default:
        return -1;
    } // end switch
  }

  @Override
  public void _vmf_setPropertyValueById(int propertyId, Object value) {
    switch(propertyId) {
      case 1: // normal property (no collection and no containment)
        setText((java.lang.String)value);
        break;
      default:
            throw new RuntimeException("Cannot set property with id="+propertyId +": property is not writable.");
    } // end switch
  }

  @Override
  public Object _vmf_getDefaultValueById(int propertyId) {

    switch(propertyId) {
      case 0:
        Object __vmf_default_value_tmpModel = _VMF_DEFAULT_VALUES[0];
        if(__vmf_default_value_tmpModel==null) {
            return null;
        } else {
            return __vmf_default_value_tmpModel;
        }

      case 1:
        Object __vmf_default_value_tmpText = _VMF_DEFAULT_VALUES[0];
        if(__vmf_default_value_tmpText==null) {
            return null;
        } else {
            return __vmf_default_value_tmpText;
        }

    } // end switch

    return null;
  }

  @Override
  public void _vmf_setDefaultValueById(int propertyId, Object defaultValue) {

    // property model
    if(propertyId == 0) { 
      throw new RuntimeException("Cannot set default value for property 'model' with id="+propertyId +": property is a containment property and not writable.");
    }

    // if the value was previously unset then we need to update
    // the value to the new default value
    boolean isSetBeforeDefaultUpdate = _vmf_isSetById(propertyId);
    _VMF_DEFAULT_VALUES[propertyId] = defaultValue;
    if(!isSetBeforeDefaultUpdate) {
      _vmf_unsetById(propertyId);
    }
  }

  @Override
  public boolean _vmf_isSetById(int propertyId) {
    return !java.util.Objects.equals(_vmf_getDefaultValueById(propertyId), _vmf_getPropertyValueById(propertyId));
  }

  @Override
  public void _vmf_unsetById(int propertyId) {
    _vmf_setPropertyValueById(propertyId, _vmf_getDefaultValueById(propertyId));
  }

  final Object[] _VMF_DEFAULT_VALUES = {
    null, // type model (containment type, no defaut value possible)  
    null  // type text   
  };

  // --------------------------------------------------------------------
  // --- Id related methods
  // --------------------------------------------------------------------

  // id management is currently not part of VMF (TODO how should we support this?)

  // --------------------------------------------------------------------
  // --- Reference methods
  // --------------------------------------------------------------------

  @Override
  public VList _vmf_referencedBy() { return this.referencedBy;}
  @Override
  public VList _vmf_references() { return this.references;}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy