package agg.attribute.impl; import java.lang.ref.WeakReference; import java.util.Enumeration; import java.util.Vector; import agg.attribute.AttrEvent; import agg.attribute.AttrObserver; import agg.attribute.AttrTuple; /** * Handling of attribute observers. * * @see agg.attribute.AttrObserver * @author $Author: olga $ * @version $Id: ChainedObserver.java,v 1.12 2010/08/23 07:30:49 olga Exp $ */ @SuppressWarnings("serial") public abstract class ChainedObserver extends ManagedObject implements AttrObserver, AttrTuple { // // Static variables and constants. protected static final int MAX_SIZE_OF_EVENT_STACK = 100; protected static int sizeOfEventStack = 0; // // Protected instance variables. /** * Container with observers of this instance, all of which implement the * AttrObserver interface. * * @see agg.attribute.AttrObserver */ protected transient final Vector<WeakReference<AttrObserver>> observers; public ChainedObserver(AttrTupleManager m) { super(m); this.observers = new Vector<WeakReference<AttrObserver>>(); } /** * removes all observer which are null */ private synchronized void removeNullObserver() { for (int i = 0; i < this.observers.size(); i++) { if (this.observers.get(i).get() == null) { this.observers.remove(i); i--; } } } // // Handling of this.observers. Part of the implementation of // agg.attribute.AttrTuple // public synchronized Enumeration<AttrObserver> getObservers() { final Vector<AttrObserver> tmp = new Vector<AttrObserver>(); // System.out.println("ChangedObserver.getObservers "+this.observers.size()); for (int i = 0; i < this.observers.size(); i++) { WeakReference<AttrObserver> wr = this.observers.get(i); if (wr.get() != null) { tmp.addElement(wr.get()); } else { // System.out.println("ChangedObserver.getObservers: remove null at "+i); this.observers.remove(i); i--; } } return tmp.elements(); } public void addObserver(AttrObserver attrObs) { if (attrObs != null) { // removeNullObserver(); boolean found = false; for (int i = 0; i < this.observers.size() && !found; i++) { try { found = attrObs == this.observers.get(i).get(); } catch (ArrayIndexOutOfBoundsException ex) { return; } } if (!found) { // System.out.println(this.observers.size()+" ChangedObserver.addObserver: "+attrObs+" "+this.observers.hashCode()); this.observers.addElement(new WeakReference<AttrObserver>(attrObs)); } } } public void addObserverAtPos(AttrObserver attrObs, int pos) { if (attrObs != null) { // removeNullObserver(); boolean found = false; for (int i = 0; i < this.observers.size() && !found; i++) { found = attrObs == this.observers.elementAt(i).get(); } if (!found) { // System.out.println(this.observers.size()+" ChangedObserver.addObserverAtPos: "+attrObs+" "+this.observers.hashCode()); this.observers.insertElementAt(new WeakReference<AttrObserver>(attrObs), pos); } } } public boolean contains(AttrObserver attrObs) { if ((attrObs == null) || (this.observers.isEmpty())) return false; for (int i = 0; i < this.observers.size(); i++) { WeakReference<AttrObserver> wr = this.observers.elementAt(i); if ((wr.get() != null) && wr.get() == attrObs) return true; } return false; } @SuppressWarnings("unused") private int findObserver(AttrObserver obj) { if ((obj == null) || (this.observers.isEmpty())) return -1; removeNullObserver(); for (int i = 0; i < this.observers.size(); i++) { WeakReference<AttrObserver> wr = this.observers.elementAt(i); if ((wr.get() != null) && wr.get() == obj) return i; } return -1; } public synchronized void removeObserver(AttrObserver attrObs) { if (attrObs == null || this.observers.isEmpty()) return; for (int i = 0; i < this.observers.size(); i++) { WeakReference<AttrObserver> wr = this.observers.elementAt(i); if (wr.get() == attrObs) { this.observers.remove(i); break; } } } protected void fireAttrChanged(int id, int index) { fireAttrChanged(id, index, index); } protected void fireAttrChanged(int id, int index0, int index1) { fireAttrChanged(new TupleEvent(this, id, index0, index1)); } protected void fireAttrChanged(TupleEvent evt) { if (evt == null) return; for (Enumeration<WeakReference<AttrObserver>> en = this.observers.elements(); en.hasMoreElements();) { WeakReference<AttrObserver> wr = en.nextElement(); if (wr.get() != null) { TupleEvent childEvt = filterEvent(wr.get(), evt); if (childEvt != null) wr.get().attributeChanged(childEvt); } } } /** Propagates the event to the this.observers, pretending to be the source. */ protected abstract void propagateEvent(TupleEvent e); /** * This method should be overridden by classes that wish to customize or * filter the actual event depending on the respective observer and/or its * own framework (index transformation, id change). If [null] is returned, * the specified observer will not get any notification this time. */ protected TupleEvent filterEvent(AttrObserver obs, TupleEvent e) { return e; } // // Being an observer oneself. Implementation of // agg.attribute.AttrObserver. /** * Per default, always save observer dependencies within the attribute * component. */ public boolean isPersistentFor(AttrTuple at) { return true; } /** * Checks if an endless event recursion took place. If so, a runtime * exception with a warning text is thrown, as this indicates an error in * the implementation. Otherwise, it calls the one of the respective * updating methods which can be overridden by subclasses . */ public void attributeChanged(AttrEvent evt) { if (++sizeOfEventStack > MAX_SIZE_OF_EVENT_STACK) { throw new RuntimeException("Infinite event recursion occured."); } TupleEvent event = (TupleEvent) evt; int msg = event.getID(); if (msg == AttrEvent.GENERAL_CHANGE) updateGeneralChange(event); else if (msg == AttrEvent.MEMBER_ADDED) updateMemberAdded(event); else if (msg == AttrEvent.MEMBER_DELETED) updateMemberDeleted(event); else if (msg == AttrEvent.MEMBER_MODIFIED) updateMemberModified(event); else if (msg == AttrEvent.MEMBER_RENAMED) updateMemberRenamed(event); else if (msg == AttrEvent.MEMBER_RETYPED) updateMemberRetyped(event); else if (msg == AttrEvent.MEMBER_VALUE_MODIFIED) updateValueModified(event); else if (msg == AttrEvent.MEMBER_VALUE_CORRECTNESS) updateValueCorrectness(event); else updateUnknownChange(event); sizeOfEventStack--; } /** * Fires the same event. Subclasses should override this method for * customized behaviour. */ protected void updateGeneralChange(TupleEvent event) { propagateEvent(event); } /** * Fires the same event. Subclasses should override this method for * customized behaviour. */ protected void updateMemberAdded(TupleEvent event) { propagateEvent(event); } /** * Fires the same event. Subclasses should override this method for * customized behaviour. */ protected void updateMemberDeleted(TupleEvent event) { propagateEvent(event); } /** * Fires the same event. Subclasses should override this method for * customized behaviour. */ protected void updateMemberModified(TupleEvent event) { propagateEvent(event); } /** * Fires the same event. Subclasses should override this method for * customized behaviour. */ protected void updateMemberRenamed(TupleEvent event) { propagateEvent(event); } /** * Fires the same event. Subclasses should override this method for * customized behaviour. */ protected void updateMemberRetyped(TupleEvent event) { propagateEvent(event); } /** * Fires the same event. Subclasses should override this method for * customized behaviour. */ protected void updateValueModified(TupleEvent event) { propagateEvent(event); } /** * Fires the same event. Subclasses should override this method for * customized behaviour. */ protected void updateValueCorrectness(TupleEvent event) { propagateEvent(event); } /** * Fires the same event. Subclasses should override this method for * customized behaviour. */ protected void updateUnknownChange(TupleEvent event) { propagateEvent(event); } /* * sets a vector of AttrObserver. This is only needed for reading objects. * The old this.observers will be replaced. */ /* private void setObservers(Vector<AttrObserver> observer) { // System.out.println("ChainedObserver.setObservers "); // System.out.println("observer : "+observer); this.observers = new Vector<WeakReference<AttrObserver>>(); if ((observer == null) || (observer.size() == 0)) return; Enumeration<AttrObserver> en = observer.elements(); while (en.hasMoreElements()) { AttrObserver e = en.nextElement(); // System.out.println(e); if (e != null) this.observers.addElement(new WeakReference<AttrObserver>(e)); } // System.out.println("ChainedObserver.setObservers END "); } */ } /* * $Log: ChainedObserver.java,v $ * Revision 1.12 2010/08/23 07:30:49 olga * tuning * * Revision 1.11 2010/03/18 18:14:34 olga * tuning * * Revision 1.10 2010/03/17 21:37:37 olga * tuning * * Revision 1.9 2010/03/16 15:53:00 olga * optimized * * Revision 1.8 2010/03/08 15:37:22 olga * code optimizing * * Revision 1.7 2008/09/25 08:02:50 olga * improved graphics update during graph transformation * * Revision 1.6 2008/06/26 14:18:46 olga * Graph visualization tuning * * Revision 1.5 2007/11/01 09:58:13 olga * Code refactoring: generic types- done * * Revision 1.4 2007/09/10 13:05:18 olga * In this update: * - package xerces2.5.0 is not used anymore; * - class com.objectspace.jgl.Pair is replaced by the agg own generic class agg.util.Pair; * - bugs fixed in: usage of PACs in rules; match completion; * usage of static method calls in attr. conditions * - graph editing: added some new features * Revision 1.3 2007/03/28 10:00:30 olga - * extensive changes of Node/Edge Type Editor, - first Undo implementation for * graphs and Node/edge Type editing and transformation, - new / reimplemented * options for layered transformation, for graph layouter - enable / disable for * NACs, attr conditions, formula - GUI tuning * * Revision 1.2 2006/08/02 09:00:57 olga Preliminary version 1.5.0 with - * multiple node type inheritance, - new implemented evolutionary graph layouter * for graph transformation sequences * * Revision 1.1 2005/08/25 11:56:57 enrico *** empty log message *** * * Revision 1.2 2005/06/20 13:37:03 olga Up to now the version 1.2.8 will be * prepared. * * Revision 1.1 2005/05/30 12:58:03 olga Version with Eclipse * * Revision 1.7 2004/12/20 14:53:47 olga Changes because of matching * optimisation. * * Revision 1.6 2004/06/09 11:32:53 olga Attribute-Eingebe/Bedingungen : NAC * kann jetzt eigene Variablen und Bedingungen haben. CP Berechnung korregiert. * * Revision 1.5 2003/03/05 18:24:21 komm sorted/optimized import statements * * Revision 1.4 2002/11/25 14:56:27 olga Der Fehler unter Windows 2000 im * AttributEditor ist endlich behoben. Es laeuft aber mit Java1.3.0 laeuft * endgueltig nicht. Also nicht Java1.3.0 benutzen! * * Revision 1.3 2002/10/04 16:36:38 olga Es gibt noch Fehler unter Window * * Revision 1.2 2002/09/23 12:23:55 komm added type graph in xt_basis, editor * and GUI * * Revision 1.1.1.1 2002/07/11 12:17:01 olga Imported sources * * Revision 1.7 2001/03/08 10:38:39 olga Testausgaben raus. * * Revision 1.6 2000/04/05 12:09:02 shultzke serialVersionUID aus V1.0.0 * generiert * * Revision 1.5 1999/09/13 14:05:35 shultzke fireAttrChanged an WeakReferences * angepasst * * Revision 1.4 1999/09/06 13:38:55 shultzke ChainedObserver auf WeakReferences * umgestellt, samt serialUID */