/** * Copyright 2004-2016 Riccardo Solmi. All rights reserved. * This file is part of the Whole Platform. * * The Whole Platform is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * The Whole Platform is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with the Whole Platform. If not, see <http://www.gnu.org/licenses/>. */ package org.whole.lang.model; import java.io.IOException; import java.io.Serializable; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.whole.lang.builders.FeaturesList; import org.whole.lang.commands.ICommand; import org.whole.lang.commands.NullCommand; import org.whole.lang.commons.factories.CommonsEntityAdapterFactory; import org.whole.lang.commons.factories.CommonsEntityFactory; import org.whole.lang.commons.model.Fragment; import org.whole.lang.commons.reflect.CommonsFeatureDescriptorEnum; import org.whole.lang.events.IChangeEventHandler; import org.whole.lang.events.IRequestEventHandler; import org.whole.lang.events.IdentityChangeEventHandler; import org.whole.lang.events.IdentityRequestEventHandler; import org.whole.lang.exceptions.WholeIllegalArgumentException; import org.whole.lang.lifecycle.IHistoryManager; import org.whole.lang.matchers.GenericMatcher; import org.whole.lang.matchers.Matcher; import org.whole.lang.operations.PrettyPrinterOperation; import org.whole.lang.reflect.EntityDescriptor; import org.whole.lang.reflect.EntityKinds; import org.whole.lang.reflect.FeatureDescriptor; import org.whole.lang.reflect.IEditorKit; import org.whole.lang.reflect.ILanguageKit; import org.whole.lang.util.EntityUtils; import org.whole.lang.util.StringUtils; import org.whole.lang.util.WholeMessages; /** * @author Riccardo Solmi */ @SuppressWarnings("serial") public abstract class AbstractEntity implements InternalIEntity, Serializable, Cloneable { transient protected boolean requestNotificationDisabled = false; transient private IRequestEventHandler requestEventHandler = IdentityRequestEventHandler.instance; transient private IChangeEventHandler changeEventHandler = IdentityChangeEventHandler.instance; transient private ICommand bindingCommand = NullCommand.instance; private IFragmentModel model = NullFragmentModel.instance; private IEntity parent = NullEntity.instance; private Map<IEntity, Integer> inverseAdjacents = null; private Map<FeatureDescriptor, IEntity> aspectualFeatures = Collections.emptyMap(); private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); requestEventHandler = IdentityRequestEventHandler.instance; changeEventHandler = IdentityChangeEventHandler.instance; bindingCommand = NullCommand.instance; } private Serializable pid; public Serializable wGetPid() { return pid; } public void wSetPid(Serializable pid) { this.pid = pid; } public boolean wIsAdapter() { return false; } @SuppressWarnings("unchecked") public <E extends IEntity> E wGetAdapter(EntityDescriptor<E> ed) { final EntityDescriptor<?> thisEd = wGetEntityDescriptor(); if (ed.isLanguageSupertypeOf(thisEd)) return (E) this; else if (ed.isPlatformSupertypeOf(thisEd)) return CommonsEntityAdapterFactory.create(ed, this); else throw new IllegalArgumentException(wGetEntityDescriptor().getName()+" is not adaptable to: "+ed.getName()); } public IEntity wGetAdaptee(boolean force) { return this; } @SuppressWarnings("unchecked") public <E extends IEntity> E wResolveWith(EntityDescriptor<E> ed) { if (ed.equals(wGetEntityDescriptor())) return (E) this; throw new IllegalArgumentException("The entity is not a resolver"); } public /*final*/ ICommand wGetBindingCommand() { return bindingCommand; } public /*final*/ void wSetBindingCommand(ICommand command) { bindingCommand = command; } public ICommand wGetLastCommand() { ICommand cmd = NullCommand.instance; int maxTime = Integer.MIN_VALUE; for (int i=0, size=wSize(); i<size; i++) { ICommand featureCmd = ((InternalIEntity) wGet(i)).wGetBindingCommand(); if (maxTime < featureCmd.getExecutionTime()) { cmd = featureCmd; maxTime = featureCmd.getExecutionTime(); } } return cmd; } public ICommand wSetLastCommand(ICommand command) { return null;//for back compatibility wGetLastCommand(); } public IFragmentModel wGetModel() { if (model == NullFragmentModel.instance) wSetModel(wGetEntityDescriptor().getLanguageKit().createFragmentModel()); return model; } protected final IFragmentModel wGetActualModel() { return model; } /* * Invariants: * - The same CompoundModel for all the containment tree * - Same FragmentModel implies same language over the connection path of entities * - An entity is the root of a FragmentModel iff is a fragment entity or the child of a fragment entity * * @see org.whole.lang.model.InternalIEntity#wSetModel(org.whole.lang.model.IFragmentModel) */ public final void wSetModel(IFragmentModel fragmentModel) { if (this.model == PrototypeFragmentModel.instance || fragmentModel == NullFragmentModel.instance) return; boolean isFragment = this instanceof Fragment; if (fragmentModel == PrototypeFragmentModel.instance) this.model = fragmentModel; else if (wGetLanguageKit().equals(fragmentModel.getLanguageKit()) && !isFragment) { if (this.model != NullFragmentModel.instance) { IHistoryManager hm = this.model.getCompoundModel().getHistoryManager(); if (!hm.equals(fragmentModel.getCompoundModel().getHistoryManager())) hm.clearHistory(); } this.model = fragmentModel; } else { if (this.model == NullFragmentModel.instance || this.model == fragmentModel) this.model = wGetEntityDescriptor().getLanguageKit().createFragmentModel();//TODO copy history this.model.setCompoundModel(fragmentModel.getCompoundModel()); this.model.setFragment(isFragment ? (Fragment) this : fragmentModel.getFragment()); } wSetChildrenModel(this.model); } protected void wSetChildrenModel(IFragmentModel model) { EntityDescriptor<?> ed = wGetEntityDescriptor(); for (int i=0, size=wSize(); i<size; i++) { InternalIEntity child = (InternalIEntity) wGet(i); if (ed.getEntityFeatureDescriptor(i).isReference()) { if (!EntityUtils.hasParent(child)) child.wSetModel(wGetActualModel()); } else child.wSetModel(model); } } public ILanguageKit wGetLanguageKit() { return wGetEntityDescriptor().getLanguageKit(); } public IEditorKit wGetEditorKit() { ILanguageKit languageKit = wGetEntityDescriptor().getLanguageKit(); IFragmentModel model = wGetActualModel(); if (model != NullFragmentModel.instance) { IEditorKit editorKit = model.getEditorKit(); if (editorKit.canApply(languageKit)) return editorKit; } return languageKit.getDefaultEditorKit(); // return model != NullFragmentModel.instance ? model.getEditorKit() : languageKit.getDefaultEditorKit(); } public int wGetEntityOrd() { return wGetEntityDescriptor().getOrdinal(); } public EntityKinds wGetEntityKind() { return EntityKinds.SIMPLE; } public abstract EntityDescriptor<?> wGetEntityDescriptor(); public IEntity wGetRoot() { IEntity fragment = wGetModel().getFragment(); return fragment != null ? fragment.wGetRoot() : NullEntity.instance; } public IEntity wGetParent() { return parent; } public void wSetParent(IEntity parent) { if (this.parent == parent) return; if (!EntityUtils.isNull(this.parent)) throw new IllegalArgumentException("The entity is already parented: "+this); this.parent = parent; } public void wRemoveParent(IEntity parent) { if (this.parent == parent) this.parent = NullEntity.instance; } public void wAddInverseAdjacent(IEntity inverseAdjacent) { if (inverseAdjacents == null) inverseAdjacents = new HashMap<IEntity, Integer>(); Integer counter = inverseAdjacents.get(inverseAdjacent); if (counter == null) inverseAdjacents.put(inverseAdjacent, new Integer(1)); else inverseAdjacents.put(inverseAdjacent, new Integer(counter.intValue() + 1)); } public void wRemoveInverseAdjacent(IEntity inverseAdjacent) { if (inverseAdjacents == null) return; //FIXME workaround for prototype initialization (composite of references) Integer counter = inverseAdjacents.get(inverseAdjacent); if (counter == null) return; int count = counter.intValue(); if (count == 1) inverseAdjacents.remove(inverseAdjacent); else inverseAdjacents.put(inverseAdjacent, new Integer(count - 1)); } public int wAdjacentSize() { return 0; } public int wInverseAdjacentSize() { return inverseAdjacents != null ? inverseAdjacents.size() : 0; } public Iterable<IEntity> wInverseAdjacents() { return inverseAdjacents != null ? inverseAdjacents.keySet() : Collections.<IEntity>emptyList(); } // public List<FeatureDescriptor> wGetAdjacentFeatureDescriptors() { // List<FeatureDescriptor> fd = wGetEntityDescriptor().getEntityFeatureDescriptors(); // return fd.subList(fd.size()-wAdjacentSize(), fd.size()); // } public Set<FeatureDescriptor> wGetAspectualFeatureDescriptors() { return aspectualFeatures.keySet(); } public void wAddRequestEventHandler(IRequestEventHandler eventHandler) { this.requestEventHandler = this.requestEventHandler.addRequestEventHandler(eventHandler); } public void wRemoveRequestEventHandler(IRequestEventHandler eventHandler) { this.requestEventHandler = this.requestEventHandler.removeRequestEventHandler(eventHandler); } protected final IRequestEventHandler wGetEntityRequestEventHandler() { return requestEventHandler; } protected final IRequestEventHandler wGetCompoundRequestEventHandler() { return wGetActualModel().getCompoundModel().getRequestEventHandler(); } public void wAddChangeEventHandler(IChangeEventHandler eventHandler) { this.changeEventHandler = this.changeEventHandler.addChangeEventHandler(eventHandler); } public void wRemoveChangeEventHandler(IChangeEventHandler eventHandler) { this.changeEventHandler = this.changeEventHandler.removeChangeEventHandler(eventHandler); } protected final IChangeEventHandler wGetEntityChangeEventHandler() { return changeEventHandler; } protected final IChangeEventHandler wGetCompoundChangeEventHandler() { return wGetActualModel().getCompoundModel().getChangeEventHandler(); } @SuppressWarnings("unchecked") public IEntity wShallowClone() { try { AbstractEntity entity = (AbstractEntity) super.clone(); entity.pid = null; entity.model = NullFragmentModel.instance; entity.parent = NullEntity.instance; entity.inverseAdjacents = null; if (!entity.aspectualFeatures.equals(Collections.EMPTY_MAP)) entity.aspectualFeatures = (Map<FeatureDescriptor, IEntity>) ((HashMap<FeatureDescriptor, IEntity>) entity.aspectualFeatures).clone(); entity.bindingCommand = NullCommand.instance; entity.requestEventHandler = entity.requestEventHandler.cloneRequestEventHandler(IdentityRequestEventHandler.instance); entity.changeEventHandler = entity.changeEventHandler.cloneChangeEventHandler(IdentityChangeEventHandler.instance); return entity; } catch (CloneNotSupportedException e) { throw new InternalError(); } } public Set<IEntity> wGetSharingSet() { if (wGetEntityChangeEventHandler().hasSharingEventHandler()) return wGetEntityChangeEventHandler().getSharingEventHandler(this).sharingSet(); return Collections.singleton((IEntity) this); } public int wHashCode() { return hashCode(); } public boolean wEquals(IEntity entity) { return equals(entity.wGetAdaptee(false)); } public String toString() { try { return PrettyPrinterOperation.toPrettyPrintString(this, 16384); } catch (RuntimeException e) { return toDebugString(); } } public String toDebugString() { StringBuffer result = new StringBuffer(); result.append(StringUtils.transientId(this)); result.append('('); toString(result); result.append(')'); return result.toString(); } protected void toString(StringBuffer buffer) { } public void wAccept(GenericMatcher matcher, IEntity other) { matcher.match(this, other); } public FeatureDescriptor wGetFeatureDescriptor(IEntity child) { return wGetEntityDescriptor().getEntityFeatureDescriptor(wIndexOf(child)); } public EntityDescriptor<?> wGetEntityDescriptor(IEntity child) { return wGetEntityDescriptor().getEntityDescriptor(wIndexOf(child)); } public List<IEntity> wFeatures() { if (wIsEmpty()) return Collections.<IEntity>emptyList(); return new FeaturesList(this); //TODO unmodifiable? } public boolean wContains(IEntity entity) { for (int i=0, size=wSize(); i<size; i++) if (wGet(i).wEquals(entity)) return true; // i could be different from wIndexOf(child) return false; } public int wIndexOf(IEntity entity) { boolean requestNotificationState = requestNotificationDisabled; requestNotificationDisabled = true; try { IEntity adaptee = entity.wGetAdaptee(false); int result = -1; for (int i=0, size=wSize()+wAdjacentSize(); i<size; i++) { IEntity child = wGet(i).wGetAdaptee(false); if (child.equals(adaptee)) return i; // object identity else if (result == -1 && child.wEquals(adaptee)) result = i; // business identity } return result; } finally { requestNotificationDisabled = requestNotificationState; } } public boolean wAdd(IEntity child) { throw new UnsupportedOperationException(WholeMessages.no_composite); } public boolean wRemove(IEntity child) { return wRemove(wIndexOf(child)); } public IEntity wGet(IEntity child) { int index = wIndexOf(child); return index != -1 ? wGet(index) : null; //TODO NullEntity.instance ? } public boolean wSet(IEntity oldChild, IEntity newChild) { ICommand cmd = ((InternalIEntity) oldChild).wGetBindingCommand(); while (cmd != NullCommand.instance && cmd.getSource() != this) cmd = cmd.getPrevCommand(); if (cmd == NullCommand.instance) { int index = wIndexOf(oldChild); if (index >= 0) { wSet(index, newChild); return true; } return false; } wSet(cmd.getSourceFeatureDescriptor(), newChild); return true; } public boolean wIsSet(IEntity child) { return wIsSet(wIndexOf(child)); } public void wUnset(IEntity child) { wUnset(wIndexOf(child)); } public boolean wIsEmpty() { return wSize() == 0; } public int wSize() { return 0; } public /*final*/ boolean wContains(int index) { return index >= 0 && index < wSize() + wAdjacentSize(); } public /*final*/ FeatureDescriptor wGetFeatureDescriptor(int index) { return wGetEntityDescriptor().getEntityFeatureDescriptor(index); } public /*final*/ EntityDescriptor<?> wGetEntityDescriptor(int index) { return wGetEntityDescriptor().getEntityDescriptor(index); } public boolean wAdd(int index, IEntity child) { throw new UnsupportedOperationException(); } public boolean wRemove(int index) { if (!wContains(index)) return false; wSet(index, CommonsEntityFactory.instance.createResolver()); return true; } public IEntity wGet(int index) { throw new IndexOutOfBoundsException(); } public void/*boolean*/ wSet(int index, IEntity child) { throw new IndexOutOfBoundsException(); } public boolean wIsSet(int index) { return wContains(index) && !EntityUtils.isDefault(this, index, wGet(index)); } public void wUnset(int index) { if (wContains(index)) EntityUtils.setDefault(this, index); } public /*final*/ boolean wContains(FeatureDescriptor fd) { //TODO add support for aspectual features return wGetEntityDescriptor().has(fd); } public /*final*/ EntityDescriptor<?> wGetEntityDescriptor(FeatureDescriptor fd) { return wGetEntityDescriptor().getEntityDescriptor(fd); } public /*final*/ int wIndexOf(FeatureDescriptor fd) { return wGetEntityDescriptor().indexOf(fd); } public boolean wRemove(FeatureDescriptor fd) { return wRemove(wIndexOf(fd)); } public /*final*/ IEntity wGet(FeatureDescriptor fd) { int index = wIndexOf(fd); if (index >= 0) return wGet(index); else { IEntity adjacent = aspectualFeatures.get(fd); if (adjacent != null) return notifyRequested(fd, adjacent); else throw new IllegalArgumentException(); } } public /*final*/ void wSet(FeatureDescriptor fd, IEntity value) { int index = wIndexOf(fd); if (index >= 0) wSet(index, value); else { if (aspectualFeatures.equals(Collections.EMPTY_MAP)) aspectualFeatures = new HashMap<FeatureDescriptor, IEntity>(); //TODO ? put efd if monomorph to avoid wContains ambiguity notifyChanged(fd, aspectualFeatures.put(fd, value), value, false); } } public boolean wIsSet(FeatureDescriptor fd) { return wIsSet(wIndexOf(fd)); } public void wUnset(FeatureDescriptor fd) { wUnset(wIndexOf(fd)); } public boolean wContainsValue(Object otherValue) { return false; } public boolean wBooleanValue() { throw new WholeIllegalArgumentException(WholeMessages.no_data); } public byte wByteValue() { throw new WholeIllegalArgumentException(WholeMessages.no_data); } public char wCharValue() { throw new WholeIllegalArgumentException(WholeMessages.no_data); } public double wDoubleValue() { throw new WholeIllegalArgumentException(WholeMessages.no_data); } public float wFloatValue() { throw new WholeIllegalArgumentException(WholeMessages.no_data); } public int wIntValue() { throw new WholeIllegalArgumentException(WholeMessages.no_data); } public long wLongValue() { throw new WholeIllegalArgumentException(WholeMessages.no_data); } public short wShortValue() { throw new WholeIllegalArgumentException(WholeMessages.no_data); } public String wStringValue() { throw new WholeIllegalArgumentException(WholeMessages.no_data); } public Date wDateValue() { throw new WholeIllegalArgumentException(WholeMessages.no_data); } public EnumValue wEnumValue() { throw new WholeIllegalArgumentException(WholeMessages.no_data); } public Object wGetValue() { throw new WholeIllegalArgumentException(WholeMessages.no_data); } public void wSetValue(boolean value) { throw new WholeIllegalArgumentException(WholeMessages.no_data); } public void wSetValue(byte value) { throw new WholeIllegalArgumentException(WholeMessages.no_data); } public void wSetValue(char value) { throw new WholeIllegalArgumentException(WholeMessages.no_data); } public void wSetValue(double value) { throw new WholeIllegalArgumentException(WholeMessages.no_data); } public void wSetValue(float value) { throw new WholeIllegalArgumentException(WholeMessages.no_data); } public void wSetValue(int value) { throw new WholeIllegalArgumentException(WholeMessages.no_data); } public void wSetValue(long value) { throw new WholeIllegalArgumentException(WholeMessages.no_data); } public void wSetValue(short value) { throw new WholeIllegalArgumentException(WholeMessages.no_data); } public void wSetValue(String value) { throw new WholeIllegalArgumentException(WholeMessages.no_data); } public void wSetValue(Date value) { throw new WholeIllegalArgumentException(WholeMessages.no_data); } public void wSetValue(EnumValue value) { throw new WholeIllegalArgumentException(WholeMessages.no_data); } public void wSetValue(Object value) { throw new WholeIllegalArgumentException(WholeMessages.no_data); } public boolean wIsSet() { throw new WholeIllegalArgumentException(WholeMessages.no_data); } public void wUnset() { throw new WholeIllegalArgumentException(WholeMessages.no_data); } @SuppressWarnings("unchecked") protected final <E extends IEntity> E notifyRequested(int index, E value) { if (requestNotificationDisabled) return value; FeatureDescriptor fd = CommonsFeatureDescriptorEnum.composite_element; IEntity value0 = value.wGetAdaptee(false); IEntity result = wGetEntityRequestEventHandler().notifyRequested(this, fd, index, value0); result = wGetCompoundRequestEventHandler().notifyRequested(this, fd, index, result); return result == value0 ? value : (E) result; } @SuppressWarnings("unchecked") protected final <E extends IEntity> E notifyRequested(FeatureDescriptor fd, E value) { if (requestNotificationDisabled) return value; IEntity value0 = value.wGetAdaptee(false); IEntity result = wGetEntityRequestEventHandler().notifyRequested(this, fd, value0); result = wGetCompoundRequestEventHandler().notifyRequested(this, fd, result); return result == value0 ? value : (E) result; } protected final boolean notifyRequested(boolean value) { if (requestNotificationDisabled) return value; FeatureDescriptor fd = CommonsFeatureDescriptorEnum.data_value; boolean result = wGetEntityRequestEventHandler().notifyRequested(this, fd, value); return wGetCompoundRequestEventHandler().notifyRequested(this, fd, result); } protected final byte notifyRequested(byte value) { if (requestNotificationDisabled) return value; FeatureDescriptor fd = CommonsFeatureDescriptorEnum.data_value; byte result = wGetEntityRequestEventHandler().notifyRequested(this, fd, value); return wGetCompoundRequestEventHandler().notifyRequested(this, fd, result); } protected final char notifyRequested(char value) { if (requestNotificationDisabled) return value; FeatureDescriptor fd = CommonsFeatureDescriptorEnum.data_value; char result = wGetEntityRequestEventHandler().notifyRequested(this, fd, value); return wGetCompoundRequestEventHandler().notifyRequested(this, fd, result); } protected final double notifyRequested(double value) { if (requestNotificationDisabled) return value; FeatureDescriptor fd = CommonsFeatureDescriptorEnum.data_value; double result = wGetEntityRequestEventHandler().notifyRequested(this, fd, value); return wGetCompoundRequestEventHandler().notifyRequested(this, fd, result); } protected final float notifyRequested(float value) { if (requestNotificationDisabled) return value; FeatureDescriptor fd = CommonsFeatureDescriptorEnum.data_value; float result = wGetEntityRequestEventHandler().notifyRequested(this, fd, value); return wGetCompoundRequestEventHandler().notifyRequested(this, fd, result); } protected final int notifyRequested(int value) { if (requestNotificationDisabled) return value; FeatureDescriptor fd = CommonsFeatureDescriptorEnum.data_value; int result = wGetEntityRequestEventHandler().notifyRequested(this, fd, value); return wGetCompoundRequestEventHandler().notifyRequested(this, fd, result); } protected final long notifyRequested(long value) { if (requestNotificationDisabled) return value; FeatureDescriptor fd = CommonsFeatureDescriptorEnum.data_value; long result = wGetEntityRequestEventHandler().notifyRequested(this, fd, value); return wGetCompoundRequestEventHandler().notifyRequested(this, fd, result); } protected final short notifyRequested(short value) { if (requestNotificationDisabled) return value; FeatureDescriptor fd = CommonsFeatureDescriptorEnum.data_value; short result = wGetEntityRequestEventHandler().notifyRequested(this, fd, value); return wGetCompoundRequestEventHandler().notifyRequested(this, fd, result); } protected final String notifyRequested(String value) { if (requestNotificationDisabled) return value; FeatureDescriptor fd = CommonsFeatureDescriptorEnum.data_value; String result = wGetEntityRequestEventHandler().notifyRequested(this, fd, value); return wGetCompoundRequestEventHandler().notifyRequested(this, fd, result); } protected final Date notifyRequested(Date value) { if (requestNotificationDisabled) return value; FeatureDescriptor fd = CommonsFeatureDescriptorEnum.data_value; Date result = wGetEntityRequestEventHandler().notifyRequested(this, fd, value); return wGetCompoundRequestEventHandler().notifyRequested(this, fd, result); } protected final java.sql.Date notifyRequested(java.sql.Date value) { return (java.sql.Date) notifyRequested((Object) value); } protected final java.sql.Time notifyRequested(java.sql.Time value) { return (java.sql.Time) notifyRequested((Object) value); } protected final java.sql.Timestamp notifyRequested(java.sql.Timestamp value) { return (java.sql.Timestamp) notifyRequested((Object) value); } protected final <E extends EnumValue> E notifyRequested(E value) { if (requestNotificationDisabled) return value; FeatureDescriptor fd = CommonsFeatureDescriptorEnum.data_value; E result = wGetEntityRequestEventHandler().notifyRequested(this, fd, value); return wGetCompoundRequestEventHandler().notifyRequested(this, fd, result); } @SuppressWarnings("unchecked") protected final <E> E notifyRequested(E value) { if (requestNotificationDisabled) return value; FeatureDescriptor fd = CommonsFeatureDescriptorEnum.data_value; Object result = wGetEntityRequestEventHandler().notifyRequested(this, fd, value); return (E) wGetCompoundRequestEventHandler().notifyRequested(this, fd, result); } public IEntity wGetOwner() { if (wGetEntityDescriptor().isRelationship()) { IEntity owner = wGetParent(); if (EntityUtils.isNull(owner) && wInverseAdjacentSize() == 1) owner = wInverseAdjacents().iterator().next(); if (!EntityUtils.isNull(owner) && owner.wGetFeatureDescriptor(this).isToMany()) return owner; } return NullEntity.instance; } protected final void notifyAdded(int index, IEntity newValue, boolean isContainment) { IEntity owner = wGetOwner(); if (!EntityUtils.isNull(owner) && EntityUtils.isNotResolver(owner)) { EntityDescriptor<?> ownerEd = owner.wGetEntityDescriptor(); FeatureDescriptor ownerFd = owner.wGetFeatureDescriptor(this); //was isContainment = !ownerEd.getEntityFeatureDescriptor(ownerFd).isReference(); FeatureDescriptor oppositeFd; EntityDescriptor<?> oppositeEd; if (ownerEd.has(ownerFd)) { oppositeEd = ownerFd.getEntityDescriptor();//ownerEd.getEntityDescriptor(ownerFd); oppositeFd = ownerFd.getOppositeFeatureDescriptor();//ownerEd.getOppositeFeatureDescriptor(ownerFd); } else { oppositeEd = newValue.wGetEntityDescriptor(); oppositeFd = oppositeEd.getDirectFeatureDescriptor(ownerFd); if (oppositeFd != null) ownerEd = oppositeEd.getEntityDescriptor(oppositeFd); } final EntityDescriptor<?> featureEd = ownerEd.getEntityDescriptor(ownerFd); final boolean isToMany = featureEd.isToManyRelationship(); final boolean isToManyImpl = isToMany && Matcher.matchImpl(featureEd, this); if (oppositeFd != null && isToManyImpl) newValue.wAdd(oppositeFd, owner, true); } final InternalIEntity internalNewValue = (InternalIEntity) newValue; if (isContainment) { internalNewValue.wSetModel(wGetActualModel()); internalNewValue.wSetParent(this); } else { if (!EntityUtils.hasParent(newValue)) internalNewValue.wSetModel(wGetActualModel()); internalNewValue.wAddInverseAdjacent(this); } FeatureDescriptor fd = CommonsFeatureDescriptorEnum.composite_element; IEntity newValue0 = newValue.wGetAdaptee(false); wGetEntityChangeEventHandler().notifyAdded(this, fd, index, newValue0); wGetCompoundChangeEventHandler().notifyAdded(this, fd, index, newValue0); } protected final void notifyRemoved(int index, IEntity oldValue, boolean isContainment) { final InternalIEntity internalOldValue = (InternalIEntity) oldValue; if (isContainment) internalOldValue.wRemoveParent(this); else internalOldValue.wRemoveInverseAdjacent(this); FeatureDescriptor fd = CommonsFeatureDescriptorEnum.composite_element; IEntity oldValue0 = oldValue.wGetAdaptee(false); wGetEntityChangeEventHandler().notifyRemoved(this, fd, index, oldValue0); wGetCompoundChangeEventHandler().notifyRemoved(this, fd, index, oldValue0); } protected final void notifyChanged(int index, IEntity oldValue, IEntity newValue, boolean isContainment) { final IEntity oldValue0 = oldValue.wGetAdaptee(false); final IEntity newValue0 = newValue.wGetAdaptee(false); if (newValue0 == oldValue0) return; final InternalIEntity internalOldValue = (InternalIEntity) oldValue; final InternalIEntity internalNewValue = (InternalIEntity) newValue; if (isContainment) { internalOldValue.wRemoveParent(this); internalNewValue.wSetModel(wGetActualModel()); internalNewValue.wSetParent(this); } else { internalOldValue.wRemoveInverseAdjacent(this); if (!EntityUtils.hasParent(newValue)) internalNewValue.wSetModel(wGetActualModel()); internalNewValue.wAddInverseAdjacent(this); } FeatureDescriptor fd = wGetFeatureDescriptor(index); wGetEntityChangeEventHandler().notifyChanged(this, fd, index, oldValue0, newValue0); // wGetFragmentChangeEventHandler().notifyChanged(this, fd, index, oldValue0, newValue0); wGetCompoundChangeEventHandler().notifyChanged(this, fd, index, oldValue0, newValue0); } protected final void notifyChanged(IEntity oldValue, IEntity newValue, boolean isContainment) { notifyChanged(CommonsFeatureDescriptorEnum.composite_element, oldValue, newValue, isContainment); } protected final void notifyChanged(FeatureDescriptor fd, IEntity oldValue, IEntity newValue) { notifyChanged(fd, oldValue, newValue, true); } protected final void notifyChanged(FeatureDescriptor fd, IEntity oldValue, IEntity newValue, boolean isContainment) { if (oldValue == null) oldValue = NullEntity.instance; final IEntity oldValue0 = oldValue.wGetAdaptee(false); final IEntity newValue0 = newValue.wGetAdaptee(false); if (newValue0 == oldValue0) return; final InternalIEntity internalOldValue = (InternalIEntity) oldValue; final InternalIEntity internalNewValue = (InternalIEntity) newValue; EntityDescriptor<?> thisEd = wGetEntityDescriptor(); FeatureDescriptor oppositeFd; if (thisEd.has(fd)) oppositeFd = thisEd.getEntityFeatureDescriptor(fd).getOppositeFeatureDescriptor();//getOppositeFeatureDescriptor(fd); else { EntityDescriptor<?> oppositeEd = newValue.wGetEntityDescriptor(); oppositeFd = oppositeEd.getDirectFeatureDescriptor(fd); if (oppositeFd != null) thisEd = oppositeEd.getEntityDescriptor(oppositeFd); } if (oppositeFd != null) { final EntityDescriptor<?> featureEd = thisEd.getEntityDescriptor(fd); final boolean isToMany = featureEd.isToManyRelationship(); final boolean wasToManyImpl = isToMany && Matcher.matchImpl(featureEd, oldValue); final boolean isToManyImpl = isToMany && Matcher.matchImpl(featureEd, newValue); if (wasToManyImpl) for (int i=0, size=oldValue.wSize(); i<size; i++) oldValue.wGet(i).wRemove(oppositeFd, this); else oldValue.wRemove(oppositeFd, this); if (isToManyImpl) for (int i=0, size=newValue.wSize(); i<size; i++) newValue.wGet(i).wAdd(oppositeFd, this, true); else newValue.wAdd(oppositeFd, this, true); } if (isContainment) { internalOldValue.wRemoveParent(this); internalNewValue.wSetModel(wGetActualModel()); internalNewValue.wSetParent(this); } else { internalOldValue.wRemoveInverseAdjacent(this); if (!EntityUtils.hasParent(newValue)) internalNewValue.wSetModel(wGetActualModel()); internalNewValue.wAddInverseAdjacent(this); } wGetEntityChangeEventHandler().notifyChanged(this, fd, oldValue0, newValue0); wGetCompoundChangeEventHandler().notifyChanged(this, fd, oldValue0, newValue0); } public boolean wAdd(FeatureDescriptor fd, IEntity value, boolean forceUnique) { if (EntityUtils.isResolver(this)) return false;//TODO move into AbstractEntityResolver EntityDescriptor<?> asEd = wGetEntityDescriptor();//TODO workaround for aspectual features if (asEd.has(fd)) { final EntityDescriptor<?> featureEd = asEd.getEntityDescriptor(fd); if (featureEd.isToManyRelationship()) { final IEntity oldValue = wGet(fd); if (EntityUtils.isResolver(oldValue)) return oldValue.wAdd(value); else if (Matcher.matchImpl(featureEd, oldValue)) { int valueIndex; if (forceUnique && (valueIndex = oldValue.wIndexOf(value)) >=0 && value.equals(oldValue.wGet(valueIndex))) return false; else return oldValue.wAdd(value); } } } wSet(fd, value); return true; } public boolean wRemove(FeatureDescriptor fd, IEntity value) { if (EntityUtils.isResolver(this)) return false;//TODO move into AbstractEntityResolver EntityDescriptor<?> asEd = wGetEntityDescriptor();//TODO workaround for aspectual features if (asEd.has(fd)) { final EntityDescriptor<?> featureEd = asEd.getEntityDescriptor(fd); if (featureEd.isToManyRelationship()) { final IEntity oldValue = wGet(fd); if (Matcher.matchImpl(featureEd, oldValue)) return oldValue.wRemove(value); } } return wRemove(fd); } protected final void notifyChanged(boolean oldValue, boolean newValue) { if (newValue == oldValue) return; FeatureDescriptor fd = CommonsFeatureDescriptorEnum.data_value; wGetEntityChangeEventHandler().notifyChanged(this, fd, oldValue, newValue); wGetCompoundChangeEventHandler().notifyChanged(this, fd, oldValue, newValue); } protected final void notifyChanged(byte oldValue, byte newValue) { if (newValue == oldValue) return; FeatureDescriptor fd = CommonsFeatureDescriptorEnum.data_value; wGetEntityChangeEventHandler().notifyChanged(this, fd, oldValue, newValue); wGetCompoundChangeEventHandler().notifyChanged(this, fd, oldValue, newValue); } protected final void notifyChanged(char oldValue, char newValue) { if (newValue == oldValue) return; FeatureDescriptor fd = CommonsFeatureDescriptorEnum.data_value; wGetEntityChangeEventHandler().notifyChanged(this, fd, oldValue, newValue); wGetCompoundChangeEventHandler().notifyChanged(this, fd, oldValue, newValue); } protected final void notifyChanged(double oldValue, double newValue) { if (newValue == oldValue) return; FeatureDescriptor fd = CommonsFeatureDescriptorEnum.data_value; wGetEntityChangeEventHandler().notifyChanged(this, fd, oldValue, newValue); wGetCompoundChangeEventHandler().notifyChanged(this, fd, oldValue, newValue); } protected final void notifyChanged(float oldValue, float newValue) { if (newValue == oldValue) return; FeatureDescriptor fd = CommonsFeatureDescriptorEnum.data_value; wGetEntityChangeEventHandler().notifyChanged(this, fd, oldValue, newValue); wGetCompoundChangeEventHandler().notifyChanged(this, fd, oldValue, newValue); } protected final void notifyChanged(int oldValue, int newValue) { if (newValue == oldValue) return; FeatureDescriptor fd = CommonsFeatureDescriptorEnum.data_value; wGetEntityChangeEventHandler().notifyChanged(this, fd, oldValue, newValue); wGetCompoundChangeEventHandler().notifyChanged(this, fd, oldValue, newValue); } protected final void notifyChanged(long oldValue, long newValue) { if (newValue == oldValue) return; FeatureDescriptor fd = CommonsFeatureDescriptorEnum.data_value; wGetEntityChangeEventHandler().notifyChanged(this, fd, oldValue, newValue); wGetCompoundChangeEventHandler().notifyChanged(this, fd, oldValue, newValue); } protected final void notifyChanged(short oldValue, short newValue) { if (newValue == oldValue) return; FeatureDescriptor fd = CommonsFeatureDescriptorEnum.data_value; wGetEntityChangeEventHandler().notifyChanged(this, fd, oldValue, newValue); wGetCompoundChangeEventHandler().notifyChanged(this, fd, oldValue, newValue); } protected final void notifyChanged(String oldValue, String newValue) { if (newValue != null && newValue.equals(oldValue)) return; FeatureDescriptor fd = CommonsFeatureDescriptorEnum.data_value; wGetEntityChangeEventHandler().notifyChanged(this, fd, oldValue, newValue); wGetCompoundChangeEventHandler().notifyChanged(this, fd, oldValue, newValue); } protected final void notifyChanged(Date oldValue, Date newValue) { if (newValue != null && newValue.equals(oldValue)) return; FeatureDescriptor fd = CommonsFeatureDescriptorEnum.data_value; wGetEntityChangeEventHandler().notifyChanged(this, fd, oldValue, newValue); wGetCompoundChangeEventHandler().notifyChanged(this, fd, oldValue, newValue); } protected final void notifyChanged(java.sql.Date oldValue, java.sql.Date newValue) { notifyChanged((Object) oldValue, (Object) newValue); } protected final void notifyChanged(java.sql.Time oldValue, java.sql.Time newValue) { notifyChanged((Object) oldValue, (Object) newValue); } protected final void notifyChanged(java.sql.Timestamp oldValue, java.sql.Timestamp newValue) { notifyChanged((Object) oldValue, (Object) newValue); } protected final void notifyChanged(EnumValue oldValue, EnumValue newValue) { if (newValue != null && newValue.equals(oldValue)) return; FeatureDescriptor fd = CommonsFeatureDescriptorEnum.data_value; wGetEntityChangeEventHandler().notifyChanged(this, fd, oldValue, newValue); wGetCompoundChangeEventHandler().notifyChanged(this, fd, oldValue, newValue); } protected final void notifyChanged(Object oldValue, Object newValue) { if (newValue == oldValue || (newValue != null && oldValue != null && newValue.equals(oldValue))) return; FeatureDescriptor fd = CommonsFeatureDescriptorEnum.data_value; wGetEntityChangeEventHandler().notifyChanged(this, fd, oldValue, newValue); wGetCompoundChangeEventHandler().notifyChanged(this, fd, oldValue, newValue); } }