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