0001: /*
0002: * Copyright (C) 2004 NNL Technology AB
0003: * Visit www.infonode.net for information about InfoNode(R)
0004: * products and how to contact NNL Technology AB.
0005: *
0006: * This program is free software; you can redistribute it and/or
0007: * modify it under the terms of the GNU General Public License
0008: * as published by the Free Software Foundation; either version 2
0009: * of the License, or (at your option) any later version.
0010: *
0011: * This program is distributed in the hope that it will be useful,
0012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0014: * GNU General Public License for more details.
0015: *
0016: * You should have received a copy of the GNU General Public License
0017: * along with this program; if not, write to the Free Software
0018: * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
0019: * MA 02111-1307, USA.
0020: */
0021:
0022: // $Id: PropertyMapImpl.java,v 1.28 2005/12/04 13:46:06 jesper Exp $
0023: package net.infonode.properties.propertymap;
0024:
0025: import net.infonode.properties.base.Property;
0026: import net.infonode.properties.base.exception.InvalidPropertyException;
0027: import net.infonode.properties.propertymap.ref.*;
0028: import net.infonode.properties.propertymap.value.PropertyRefValue;
0029: import net.infonode.properties.propertymap.value.PropertyValue;
0030: import net.infonode.properties.propertymap.value.ValueDecoder;
0031: import net.infonode.properties.util.PropertyChangeListener;
0032: import net.infonode.properties.util.PropertyPath;
0033: import net.infonode.util.Printer;
0034: import net.infonode.util.Utils;
0035: import net.infonode.util.ValueChange;
0036: import net.infonode.util.collection.map.ConstVectorMap;
0037: import net.infonode.util.collection.map.MapAdapter;
0038: import net.infonode.util.collection.map.SingleValueMap;
0039: import net.infonode.util.collection.map.base.ConstMap;
0040: import net.infonode.util.collection.map.base.ConstMapIterator;
0041: import net.infonode.util.collection.map.base.MapIterator;
0042: import net.infonode.util.collection.notifymap.AbstractConstChangeNotifyMap;
0043: import net.infonode.util.collection.notifymap.ChangeNotifyMapWrapper;
0044: import net.infonode.util.collection.notifymap.ConstChangeNotifyMap;
0045: import net.infonode.util.collection.notifymap.ConstChangeNotifyVectorMap;
0046: import net.infonode.util.signal.Signal;
0047: import net.infonode.util.signal.SignalListener;
0048:
0049: import java.io.IOException;
0050: import java.io.ObjectInputStream;
0051: import java.io.ObjectOutputStream;
0052: import java.util.*;
0053:
0054: /**
0055: * @author $Author: jesper $
0056: * @version $Revision: 1.28 $
0057: */
0058: public class PropertyMapImpl implements PropertyMap {
0059: private static final int SERIALIZE_VERSION = 1;
0060:
0061: private class PropertyObjectMap extends
0062: AbstractConstChangeNotifyMap implements SignalListener {
0063: private boolean listenerActive;
0064:
0065: PropertyObjectMap() {
0066: }
0067:
0068: protected void listenerAdded() {
0069: if (!listenerActive) {
0070: listenerActive = true;
0071: addInheritedReferences();
0072: super Map.getChangeSignal().add(this );
0073: }
0074: }
0075:
0076: public void signalEmitted(Signal signal, Object object) {
0077: ConstMap changes = (ConstMap) object;
0078: MapAdapter m = new MapAdapter();
0079:
0080: for (ConstMapIterator iterator = changes.constIterator(); iterator
0081: .atEntry(); iterator.next()) {
0082: Property property = (Property) iterator.getKey();
0083:
0084: if (propertyGroup.hasProperty(property)) {
0085: PropertyValue currentValue = (PropertyValue) values
0086: .get(property);
0087:
0088: if (currentValue == null
0089: || currentValue.getParent() != null) {
0090: ValueChange vc = (ValueChange) iterator
0091: .getValue();
0092: PropertyValue super Value = (PropertyValue) vc
0093: .getNewValue();
0094: PropertyValue newValue = super Value == null ? null
0095: : super Value
0096: .getSubValue(PropertyMapImpl.this );
0097: internalSetValue(property, newValue);
0098: m.put(property, new ValueChange(
0099: currentValue != null ? currentValue
0100: : vc.getOldValue(),
0101: newValue != null ? newValue : vc
0102: .getNewValue()));
0103: }
0104: }
0105: }
0106:
0107: if (!m.isEmpty())
0108: fireEntriesChanged(m);
0109: }
0110:
0111: protected void lastListenerRemoved() {
0112: if (listenerActive) {
0113: listenerActive = false;
0114: super Map.getChangeSignal().remove(this );
0115: removeInheritedReferences();
0116: }
0117: }
0118:
0119: public boolean checkListeners(Set visited) {
0120: for (Iterator it = getChangeSignalInternal().iterator(); it
0121: .hasNext();) {
0122: Object l = it.next();
0123:
0124: if (l instanceof PropertyRefValue) {
0125: PropertyRefValue v = (PropertyRefValue) l;
0126:
0127: if (v.getMap().checkListeners(visited))
0128: return true;
0129: }
0130: }
0131:
0132: return false;
0133: }
0134:
0135: public void updateListeners() {
0136: for (Iterator it = getChangeSignalInternal().iterator(); it
0137: .hasNext();) {
0138: if (!(it.next() instanceof PropertyRefValue)) {
0139: return;
0140: }
0141: }
0142:
0143: for (Iterator it = getChangeSignalInternal().iterator(); it
0144: .hasNext();) {
0145: Object l = it.next();
0146:
0147: if (l instanceof PropertyRefValue) {
0148: PropertyRefValue v = (PropertyRefValue) l;
0149:
0150: if (v.getMap().checkListeners(new HashSet())) {
0151: return;
0152: }
0153: }
0154: }
0155:
0156: lastListenerRemoved();
0157: }
0158:
0159: private void addInheritedReferences() {
0160: for (ConstMapIterator iterator = values.constIterator(); iterator
0161: .atEntry(); iterator.next()) {
0162: Property property = (Property) iterator.getKey();
0163: PropertyValue currentValue = (PropertyValue) values
0164: .get(property);
0165: currentValue.updateListener(true);
0166: }
0167:
0168: for (ConstMapIterator iterator = super Map.constIterator(); iterator
0169: .atEntry(); iterator.next()) {
0170: Property property = (Property) iterator.getKey();
0171:
0172: if (propertyGroup.hasProperty(property)) {
0173: PropertyValue currentValue = (PropertyValue) values
0174: .get(property);
0175:
0176: if (currentValue == null
0177: || currentValue.getParent() != null) {
0178: PropertyValue super Value = (PropertyValue) iterator
0179: .getValue();
0180: PropertyValue newValue = super Value == null ? null
0181: : super Value
0182: .getSubValue(PropertyMapImpl.this );
0183: internalSetValue(property, newValue);
0184: }
0185: }
0186: }
0187: }
0188:
0189: private void removeInheritedReferences() {
0190: ArrayList toBeRemoved = new ArrayList();
0191:
0192: for (ConstMapIterator iterator = values.constIterator(); iterator
0193: .atEntry(); iterator.next()) {
0194: Property property = (Property) iterator.getKey();
0195: PropertyValue currentValue = (PropertyValue) values
0196: .get(property);
0197:
0198: if (currentValue.getParent() != null) {
0199: currentValue.unset();
0200: toBeRemoved.add(property);
0201: } else {
0202: currentValue.updateListener(false);
0203: }
0204: }
0205:
0206: for (int i = 0; i < toBeRemoved.size(); i++) {
0207: values.remove(toBeRemoved.get(i));
0208: }
0209: }
0210:
0211: public Object get(Object key) {
0212: return vectorMap.get(key);
0213: }
0214:
0215: public boolean containsKey(Object key) {
0216: return vectorMap.containsKey(key);
0217: }
0218:
0219: public boolean containsValue(Object value) {
0220: return vectorMap.containsValue(value);
0221: }
0222:
0223: public boolean isEmpty() {
0224: return vectorMap.isEmpty();
0225: }
0226:
0227: public ConstMapIterator constIterator() {
0228: return vectorMap.constIterator();
0229: }
0230:
0231: protected void fireEntriesChanged(ConstMap changes) {
0232: super .fireEntriesChanged(changes);
0233: }
0234: }
0235:
0236: private PropertyMapGroup propertyGroup;
0237: private PropertyMapImpl parent;
0238: private PropertyMapProperty property;
0239:
0240: private ChangeNotifyMapWrapper values = new ChangeNotifyMapWrapper(
0241: new MapAdapter());
0242: private ConstChangeNotifyVectorMap super Map = new ConstChangeNotifyVectorMap();
0243: private ConstVectorMap vectorMap = new ConstVectorMap();
0244: private PropertyObjectMap map = new PropertyObjectMap();
0245:
0246: private ArrayList super Maps = new ArrayList(1);
0247: private MapAdapter childMaps = new MapAdapter();
0248:
0249: private HashMap propertyChangeListeners;
0250: private ArrayList listeners;
0251: private ArrayList treeListeners;
0252:
0253: private SignalListener mapListener;
0254:
0255: public PropertyMapImpl(PropertyMapGroup propertyGroup) {
0256: this (propertyGroup, null);
0257: }
0258:
0259: public PropertyMapImpl(PropertyMapImpl inheritFrom) {
0260: this (inheritFrom.getPropertyGroup(), inheritFrom);
0261: }
0262:
0263: public PropertyMapImpl(PropertyMapGroup propertyGroup,
0264: PropertyMapImpl super Object) {
0265: this (propertyGroup, null, null);
0266:
0267: if (super Object != null)
0268: addSuperMap(super Object);
0269: }
0270:
0271: public PropertyMapImpl(PropertyMapImpl parent,
0272: PropertyMapProperty property) {
0273: this (property.getPropertyMapGroup(), parent, property);
0274: }
0275:
0276: public PropertyMapImpl(PropertyMapGroup propertyGroup,
0277: PropertyMapImpl parent, PropertyMapProperty property) {
0278: this .parent = parent;
0279: this .property = property;
0280: this .propertyGroup = propertyGroup;
0281:
0282: Property[] properties = this .propertyGroup.getProperties();
0283:
0284: for (int i = 0; i < properties.length; i++) {
0285: if (properties[i] instanceof PropertyMapProperty) {
0286: PropertyMapProperty p = (PropertyMapProperty) properties[i];
0287: PropertyMapImpl propertyObject = new PropertyMapImpl(
0288: this , p);
0289: childMaps.put(p, propertyObject);
0290: }
0291: }
0292:
0293: vectorMap.addMap(values);
0294: vectorMap.addMap(super Map);
0295: }
0296:
0297: private boolean hasTreeListener() {
0298: return (treeListeners != null && treeListeners.size() > 0)
0299: || (parent != null && parent.hasTreeListener());
0300: }
0301:
0302: private boolean hasListener() {
0303: return hasTreeListener()
0304: || (listeners != null && listeners.size() > 0)
0305: || (propertyChangeListeners != null && propertyChangeListeners
0306: .size() > 0);
0307: }
0308:
0309: private void updateListenerRecursive() {
0310: updateListener();
0311:
0312: for (ConstMapIterator iterator = childMaps.constIterator(); iterator
0313: .atEntry(); iterator.next())
0314: ((PropertyMapImpl) iterator.getValue())
0315: .updateListenerRecursive();
0316: }
0317:
0318: private void updateListener() {
0319: if (hasListener()) {
0320: if (mapListener == null) {
0321: mapListener = new SignalListener() {
0322: public void signalEmitted(Signal signal,
0323: Object object) {
0324: PropertyMapManager.getInstance()
0325: .addMapChanges(PropertyMapImpl.this ,
0326: (ConstMap) object);
0327: }
0328: };
0329:
0330: map.getChangeSignal().add(mapListener);
0331: }
0332: } else {
0333: if (mapListener != null) {
0334: map.getChangeSignal().remove(mapListener);
0335: mapListener = null;
0336: map.updateListeners();
0337: }
0338: }
0339: }
0340:
0341: private boolean checkListeners(Set visited) {
0342: if (visited.contains(this ))
0343: return false;
0344:
0345: visited.add(this );
0346: return hasListener() || map.checkListeners(visited);
0347: }
0348:
0349: public ConstChangeNotifyMap getMap() {
0350: return map;
0351: }
0352:
0353: public PropertyMap getSuperMap() {
0354: return super Maps.size() == 0 ? null : (PropertyMap) super Maps
0355: .get(0);
0356: }
0357:
0358: public Object removeValue(Property property)
0359: throws InvalidPropertyException {
0360: checkProperty(property);
0361: PropertyValue value = (PropertyValue) values.get(property);
0362:
0363: // Can't removeValue not set values or inherited reference values
0364: if (value == null || value.getParent() != null)
0365: return null;
0366:
0367: values.remove(property);
0368:
0369: PropertyMapManager.getInstance().beginBatch();
0370:
0371: try {
0372: firePropertyValueChanged(property, new ValueChange(value,
0373: getValue(property)));
0374: } finally {
0375: PropertyMapManager.getInstance().endBatch();
0376: }
0377:
0378: return value.get(this );
0379: }
0380:
0381: private PropertyMapRef getPathFrom(PropertyMapImpl parentObject) {
0382: if (parent == null)
0383: return null;
0384:
0385: if (parent == parentObject)
0386: return new PropertyMapPropertyRef(property);
0387:
0388: PropertyMapRef parentRef = parent.getPathFrom(parentObject);
0389: return parentRef == null ? null : new CompositeMapRef(
0390: parentRef, new PropertyMapPropertyRef(property));
0391: }
0392:
0393: private PropertyMapRef getRelativePathTo(
0394: PropertyMapImpl propertyObject) {
0395: PropertyMapRef ref = propertyObject == this ? ThisPropertyMapRef.INSTANCE
0396: : propertyObject.getPathFrom(this );
0397: return ref == null ? parent == null ? null
0398: : new CompositeMapRef(ParentMapRef.INSTANCE, parent
0399: .getRelativePathTo(propertyObject)) : ref;
0400: }
0401:
0402: public Object createRelativeRef(Property fromProperty,
0403: PropertyMap toObject, Property toProperty) {
0404: PropertyValue value = setValue(fromProperty,
0405: new PropertyRefValue(this , fromProperty,
0406: getRelativePathTo((PropertyMapImpl) toObject),
0407: toProperty, null));
0408: return value == null ? null : value.getWithDefault(this );
0409: }
0410:
0411: public int getSuperMapCount() {
0412: return super Maps.size();
0413: }
0414:
0415: public void addSuperMap(PropertyMap super Map) {
0416: PropertyMapImpl super MapImpl = (PropertyMapImpl) super Map;
0417:
0418: /* if (!propertyObjectImpl.propertyGroup.isA(propertyGroup))
0419: throw new RuntimeException("Property group '" + propertyObjectImpl.propertyGroup + "¨' can't be assigned to group '" + propertyGroup + "'!");
0420: */
0421: PropertyMapManager.getInstance().beginBatch();
0422:
0423: try {
0424: addSuperMap(0, super MapImpl);
0425: } finally {
0426: PropertyMapManager.getInstance().endBatch();
0427: }
0428: }
0429:
0430: public PropertyMap removeSuperMap() {
0431: if (super Maps.size() > (parent == null ? 0 : parent.super Maps
0432: .size())) {
0433: PropertyMapImpl object = (PropertyMapImpl) super Maps.get(0);
0434: removeSuperMap(0);
0435: return object;
0436: } else
0437: return null;
0438: }
0439:
0440: public boolean removeSuperMap(PropertyMap super Map) {
0441: if (super Maps.size() > (parent == null ? 0 : parent.super Maps
0442: .size())) {
0443: int index = super Maps.indexOf(super Map);
0444:
0445: if (index == -1)
0446: return false;
0447: else {
0448: removeSuperMap(index);
0449: return true;
0450: }
0451: } else
0452: return false;
0453: }
0454:
0455: public boolean replaceSuperMap(PropertyMap oldSuperMap,
0456: PropertyMap newSuperMap) {
0457: if (oldSuperMap != newSuperMap
0458: && super Maps.size() > (parent == null ? 0
0459: : parent.super Maps.size())) {
0460: int index = super Maps.indexOf(oldSuperMap);
0461:
0462: if (index == -1)
0463: return false;
0464: else {
0465: PropertyMapManager.getInstance().beginBatch();
0466:
0467: try {
0468: removeSuperMap(index);
0469: addSuperMap(index, (PropertyMapImpl) newSuperMap);
0470: } finally {
0471: PropertyMapManager.getInstance().endBatch();
0472: }
0473:
0474: return true;
0475: }
0476: } else
0477: return false;
0478: }
0479:
0480: private void removeParentSuperMap(int parentIndex) {
0481: removeSuperMap(super Maps.size() - parent.super Maps.size() - 1
0482: + parentIndex);
0483: }
0484:
0485: private void removeSuperMap(int index) {
0486: PropertyMapManager.getInstance().beginBatch();
0487:
0488: try {
0489: super Map.removeMap(index);
0490: super Maps.remove(index);
0491:
0492: for (ConstMapIterator iterator = childMaps.constIterator(); iterator
0493: .atEntry(); iterator.next()) {
0494: ((PropertyMapImpl) iterator.getValue())
0495: .removeParentSuperMap(index);
0496: }
0497: } finally {
0498: PropertyMapManager.getInstance().endBatch();
0499: }
0500: }
0501:
0502: private void addSuperMap(PropertyMapImpl propertyObjectImpl) {
0503: addSuperMap(0, propertyObjectImpl);
0504: }
0505:
0506: private void addParentSuperMap(PropertyMapImpl propertyObjectImpl,
0507: int parentIndex) {
0508: addSuperMap(super Maps.size() - parent.super Maps.size() + 1
0509: + parentIndex, propertyObjectImpl);
0510: }
0511:
0512: private void addSuperMap(int index,
0513: PropertyMapImpl propertyObjectImpl) {
0514: PropertyMapManager.getInstance().beginBatch();
0515:
0516: try {
0517: super Map.addMap(index, propertyObjectImpl.map);
0518: super Maps.add(index, propertyObjectImpl);
0519:
0520: for (ConstMapIterator iterator = childMaps.constIterator(); iterator
0521: .atEntry(); iterator.next()) {
0522: ((PropertyMapImpl) iterator.getValue())
0523: .addParentSuperMap(
0524: propertyObjectImpl
0525: .getChildMapImpl((PropertyMapProperty) iterator
0526: .getKey()), index);
0527: }
0528: } finally {
0529: PropertyMapManager.getInstance().endBatch();
0530: }
0531: }
0532:
0533: public void addTreeListener(PropertyMapTreeListener listener) {
0534: if (treeListeners == null)
0535: treeListeners = new ArrayList(2);
0536:
0537: treeListeners.add(listener);
0538: updateListenerRecursive();
0539: }
0540:
0541: public void removeTreeListener(PropertyMapTreeListener listener) {
0542: if (treeListeners != null) {
0543: treeListeners.remove(listener);
0544:
0545: if (treeListeners.size() == 0)
0546: treeListeners = null;
0547:
0548: updateListenerRecursive();
0549: }
0550: }
0551:
0552: public void addListener(PropertyMapListener listener) {
0553: if (listeners == null)
0554: listeners = new ArrayList(2);
0555:
0556: listeners.add(listener);
0557: updateListener();
0558: }
0559:
0560: public void removeListener(PropertyMapListener listener) {
0561: if (listeners != null) {
0562: listeners.remove(listener);
0563:
0564: if (listeners.size() == 0)
0565: listeners = null;
0566: }
0567:
0568: updateListener();
0569: }
0570:
0571: public PropertyMapGroup getPropertyGroup() {
0572: return propertyGroup;
0573: }
0574:
0575: public void addPropertyChangeListener(Property property,
0576: PropertyChangeListener listener) {
0577: if (propertyChangeListeners == null)
0578: propertyChangeListeners = new HashMap(4);
0579:
0580: ArrayList list = (ArrayList) propertyChangeListeners
0581: .get(property);
0582:
0583: if (list == null) {
0584: list = new ArrayList(2);
0585: propertyChangeListeners.put(property, list);
0586: }
0587:
0588: list.add(listener);
0589: updateListener();
0590: }
0591:
0592: public void removePropertyChangeListener(Property property,
0593: PropertyChangeListener listener) {
0594: if (propertyChangeListeners != null) {
0595: ArrayList list = (ArrayList) propertyChangeListeners
0596: .get(property);
0597:
0598: if (list == null)
0599: return;
0600:
0601: list.remove(listener);
0602:
0603: if (list.isEmpty()) {
0604: propertyChangeListeners.remove(property);
0605:
0606: if (propertyChangeListeners.isEmpty())
0607: propertyChangeListeners = null;
0608: }
0609:
0610: updateListener();
0611: }
0612: }
0613:
0614: public PropertyMapImpl getParent() {
0615: return parent;
0616: }
0617:
0618: public PropertyMapProperty getProperty() {
0619: return property;
0620: }
0621:
0622: private void checkProperty(Property property) {
0623: if (!propertyGroup.hasProperty(property))
0624: throw new InvalidPropertyException(property, "Property '"
0625: + property + "' not found in object '"
0626: + propertyGroup + "'!");
0627: }
0628:
0629: public PropertyMap getChildMap(PropertyMapProperty property) {
0630: return getChildMapImpl(property);
0631: }
0632:
0633: public PropertyMapImpl getChildMapImpl(PropertyMapProperty property) {
0634: checkProperty(property);
0635: return (PropertyMapImpl) childMaps.get(property);
0636: }
0637:
0638: private PropertyValue getParentDefaultValue(PropertyPath path) {
0639: PropertyValue value = parent == null ? null
0640: : parent.getParentDefaultValue(new PropertyPath(
0641: property, path));
0642: return value == null ? ((PropertyMapImpl) propertyGroup
0643: .getDefaultMap()).getValue(path) : value;
0644: }
0645:
0646: public PropertyValue getValueWithDefault(Property property) {
0647: PropertyValue value = getValue(property);
0648: return value == null ? getParentDefaultValue(new PropertyPath(
0649: property)) : value;
0650: }
0651:
0652: private PropertyValue getValue(PropertyPath propertyPath) {
0653: return propertyPath.getTail() == null ? getValue(propertyPath
0654: .getProperty()) : getChildMapImpl(
0655: (PropertyMapProperty) propertyPath.getProperty())
0656: .getValue(propertyPath.getTail());
0657: }
0658:
0659: public PropertyValue getValue(Property property) {
0660: checkProperty(property);
0661: return (PropertyValue) map.get(property);
0662: }
0663:
0664: private PropertyValue internalSetValue(Property property,
0665: PropertyValue value) {
0666: PropertyValue oldValue = (PropertyValue) (value == null ? values
0667: .remove(property)
0668: : values.put(property, value));
0669:
0670: if (value != null)
0671: value.updateListener(hasListener());
0672:
0673: if (oldValue != null)
0674: oldValue.unset();
0675:
0676: return oldValue;
0677: }
0678:
0679: public PropertyValue setValue(Property property, PropertyValue value) {
0680: checkProperty(property);
0681: PropertyValue oldValue = getValue(property);
0682: internalSetValue(property, value);
0683:
0684: if (!Utils.equals(value, oldValue)) {
0685: PropertyMapManager.getInstance().beginBatch();
0686:
0687: try {
0688: firePropertyValueChanged(property, new ValueChange(
0689: oldValue, value));
0690: } finally {
0691: PropertyMapManager.getInstance().endBatch();
0692: }
0693: }
0694:
0695: return oldValue;
0696: }
0697:
0698: public boolean valueIsSet(Property property) {
0699: PropertyValue value = (PropertyValue) values.get(property);
0700: return value != null && value.getParent() == null;
0701: }
0702:
0703: public void firePropertyValueChanged(Property property,
0704: ValueChange change) {
0705: map.fireEntriesChanged(new SingleValueMap(property, change));
0706: }
0707:
0708: protected void firePropertyTreeValuesChanged(Map changes) {
0709: if (treeListeners != null) {
0710: PropertyMapTreeListener[] l = (PropertyMapTreeListener[]) treeListeners
0711: .toArray(new PropertyMapTreeListener[treeListeners
0712: .size()]);
0713:
0714: for (int i = 0; i < l.length; i++)
0715: l[i].propertyValuesChanged(changes);
0716: }
0717: }
0718:
0719: void firePropertyValuesChanged(Map changes) {
0720: if (listeners != null) {
0721: PropertyMapListener[] l = (PropertyMapListener[]) listeners
0722: .toArray(new PropertyMapListener[listeners.size()]);
0723:
0724: for (int i = 0; i < l.length; i++)
0725: l[i].propertyValuesChanged(this , changes);
0726: }
0727:
0728: if (propertyChangeListeners != null) {
0729: for (Iterator iterator = changes.entrySet().iterator(); iterator
0730: .hasNext();) {
0731: Map.Entry entry = (Map.Entry) iterator.next();
0732: ArrayList list = (ArrayList) propertyChangeListeners
0733: .get(entry.getKey());
0734:
0735: if (list != null) {
0736: ValueChange vc = (ValueChange) entry.getValue();
0737: PropertyChangeListener[] l = (PropertyChangeListener[]) list
0738: .toArray(new PropertyChangeListener[list
0739: .size()]);
0740:
0741: for (int i = 0; i < l.length; i++)
0742: l[i].propertyChanged((Property) entry.getKey(),
0743: this , vc.getOldValue(), vc
0744: .getNewValue());
0745: }
0746: }
0747: }
0748: }
0749:
0750: public void dump() {
0751: dump(new Printer(), new HashSet(4));
0752: }
0753:
0754: public void dump(Printer printer, Set printed) {
0755: printed.add(this );
0756:
0757: for (ConstMapIterator iterator = values.constIterator(); iterator
0758: .atEntry(); iterator.next()) {
0759: printer.println(iterator.getKey() + " = "
0760: + iterator.getValue());
0761: }
0762:
0763: if (!values.isEmpty())
0764: printer.println();
0765:
0766: for (int i = 0; i < super Maps.size(); i++) {
0767: /* if (printed.contains(superMaps.get(i)))
0768: continue;
0769: */
0770: printer.println("Super Object " + (i + 1) + ':');
0771: printer.beginSection();
0772: ((PropertyMapImpl) super Maps.get(i)).dump(printer, printed);
0773: printer.endSection();
0774: printer.println();
0775: }
0776:
0777: for (ConstMapIterator iterator = childMaps.constIterator(); iterator
0778: .atEntry(); iterator.next()) {
0779: printer.println(iterator.getKey() + ":");
0780: printer.beginSection();
0781: ((PropertyMapImpl) iterator.getValue()).dump(printer,
0782: printed);
0783: printer.endSection();
0784: printer.println();
0785: }
0786: }
0787:
0788: public void dumpSuperMaps(Printer printer) {
0789: printer.println(System.identityHashCode(this ) + ":" + this );
0790:
0791: for (int i = 0; i < super Maps.size(); i++) {
0792: // if (superMap.getMap(i) != ((PropertyMapImpl) superMaps.get(i)).map)
0793: // System.out.println("Error!");
0794:
0795: printer.beginSection();
0796: ((PropertyMapImpl) super Maps.get(i)).dumpSuperMaps(printer);
0797: printer.endSection();
0798: }
0799:
0800: }
0801:
0802: public void clear(boolean recursive) {
0803: PropertyMapManager.getInstance().beginBatch();
0804:
0805: try {
0806: doClear(recursive);
0807: } finally {
0808: PropertyMapManager.getInstance().endBatch();
0809: }
0810: }
0811:
0812: private void doClear(boolean recursive) {
0813: ArrayList items = new ArrayList(10);
0814:
0815: for (MapIterator iterator = values.iterator(); iterator
0816: .atEntry(); iterator.next()) {
0817: PropertyValue value = (PropertyValue) iterator.getValue();
0818:
0819: if (value.getParent() == null)
0820: items.add(iterator.getKey());
0821: }
0822:
0823: for (int i = 0; i < items.size(); i++)
0824: removeValue((Property) items.get(i));
0825:
0826: if (recursive) {
0827: for (ConstMapIterator iterator = childMaps.constIterator(); iterator
0828: .atEntry(); iterator.next()) {
0829: ((PropertyMapImpl) iterator.getValue())
0830: .doClear(recursive);
0831: }
0832: }
0833: }
0834:
0835: public boolean isEmpty(boolean recursive) {
0836: for (ConstMapIterator iterator = values.constIterator(); iterator
0837: .atEntry(); iterator.next()) {
0838: PropertyValue value = (PropertyValue) iterator.getValue();
0839:
0840: if (value.getParent() == null)
0841: return false;
0842: }
0843:
0844: if (recursive) {
0845: for (ConstMapIterator iterator = childMaps.constIterator(); iterator
0846: .atEntry(); iterator.next()) {
0847: if (!((PropertyMapImpl) iterator.getValue())
0848: .isEmpty(recursive))
0849: return false;
0850: }
0851: }
0852:
0853: return true;
0854: }
0855:
0856: private void doRead(ObjectInputStream in) throws IOException {
0857: while (in.readBoolean()) {
0858: String propertyName = in.readUTF();
0859: Property property = getPropertyGroup().getProperty(
0860: propertyName);
0861: PropertyValue value = ValueDecoder.decode(in, this ,
0862: property);
0863:
0864: if (property != null && value != null)
0865: setValue(property, value);
0866: }
0867:
0868: while (in.readBoolean()) {
0869: PropertyMapProperty property = (PropertyMapProperty) getPropertyGroup()
0870: .getProperty(in.readUTF());
0871: getChildMapImpl(property).doRead(in);
0872: }
0873: }
0874:
0875: public void write(ObjectOutputStream out, boolean recursive)
0876: throws IOException {
0877: out.writeInt(SERIALIZE_VERSION);
0878: doWrite(out, recursive);
0879: }
0880:
0881: public void write(ObjectOutputStream out) throws IOException {
0882: write(out, true);
0883: }
0884:
0885: private void doWrite(ObjectOutputStream out, boolean recursive)
0886: throws IOException {
0887: for (ConstMapIterator iterator = values.constIterator(); iterator
0888: .atEntry(); iterator.next()) {
0889: PropertyValue value = (PropertyValue) iterator.getValue();
0890: if (value.getParent() == null && value.isSerializable()) {
0891: out.writeBoolean(true);
0892: out.writeUTF(((Property) iterator.getKey()).getName());
0893: value.write(out);
0894: }
0895: }
0896:
0897: out.writeBoolean(false);
0898:
0899: if (recursive) {
0900: for (ConstMapIterator iterator = childMaps.constIterator(); iterator
0901: .atEntry(); iterator.next()) {
0902: if (!((PropertyMapImpl) iterator.getValue())
0903: .isEmpty(true)) {
0904: out.writeBoolean(true);
0905: out.writeUTF(((Property) iterator.getKey())
0906: .getName());
0907: ((PropertyMapImpl) iterator.getValue()).doWrite(
0908: out, recursive);
0909: }
0910: }
0911: }
0912:
0913: out.writeBoolean(false);
0914: }
0915:
0916: public void read(ObjectInputStream in) throws IOException {
0917: PropertyMapManager.getInstance().beginBatch();
0918:
0919: try {
0920: int version = in.readInt();
0921:
0922: if (version > SERIALIZE_VERSION)
0923: throw new IOException(
0924: "Can't read object because serialized version is newer than current version!");
0925:
0926: doRead(in);
0927: } finally {
0928: PropertyMapManager.getInstance().endBatch();
0929: }
0930: }
0931:
0932: public static void skip(ObjectInputStream in) throws IOException {
0933: int version = in.readInt();
0934:
0935: if (version > SERIALIZE_VERSION)
0936: throw new IOException(
0937: "Can't read object because serialized version is newer than current version!");
0938:
0939: doSkip(in);
0940: }
0941:
0942: private static void doSkip(ObjectInputStream in) throws IOException {
0943: while (in.readBoolean()) {
0944: in.readUTF();
0945: ValueDecoder.skip(in);
0946: }
0947:
0948: while (in.readBoolean()) {
0949: in.readUTF();
0950: doSkip(in);
0951: }
0952: }
0953:
0954: private boolean doValuesEqual(PropertyMapImpl propertyObject,
0955: boolean recursive) {
0956: for (ConstMapIterator iterator = map.constIterator(); iterator
0957: .atEntry(); iterator.next()) {
0958: Property property = (Property) iterator.getKey();
0959:
0960: if (!Utils.equals(((PropertyValue) iterator.getValue())
0961: .get(this ), propertyObject.getValue(property).get(
0962: this )))
0963: return false;
0964: }
0965:
0966: if (recursive) {
0967: for (ConstMapIterator iterator = childMaps.constIterator(); iterator
0968: .atEntry(); iterator.next()) {
0969: PropertyMapProperty property = (PropertyMapProperty) iterator
0970: .getKey();
0971:
0972: if (!((PropertyMapImpl) iterator.getValue())
0973: .doValuesEqual(propertyObject
0974: .getChildMapImpl(property), recursive))
0975: return false;
0976: }
0977: }
0978:
0979: return true;
0980: }
0981:
0982: public boolean valuesEqualTo(PropertyMap propertyObject,
0983: boolean recursive) {
0984: return doValuesEqual((PropertyMapImpl) propertyObject,
0985: recursive);
0986: }
0987:
0988: public PropertyMap copy(boolean copySuperMaps, boolean recursive) {
0989: PropertyMapImpl map = new PropertyMapImpl(propertyGroup);
0990: doCopy(map, copySuperMaps, recursive, true);
0991: return map;
0992: }
0993:
0994: private void doCopy(PropertyMapImpl map, boolean copySuperMaps,
0995: boolean recursive, boolean topMap) {
0996: for (ConstMapIterator iterator = values.constIterator(); iterator
0997: .atEntry(); iterator.next()) {
0998: PropertyValue value = (PropertyValue) iterator.getValue();
0999:
1000: if (value.getParent() == null) {
1001: map.values.put(iterator.getKey(), value.copyTo(map));
1002: }
1003: }
1004:
1005: if (copySuperMaps) {
1006: for (int i = 0; i < (topMap ? super Maps.size() : super Maps
1007: .size()
1008: - parent.super Maps.size()); i++)
1009: map.addSuperMap((PropertyMapImpl) super Maps.get(i));
1010: }
1011:
1012: if (recursive) {
1013: for (ConstMapIterator iterator = childMaps.constIterator(); iterator
1014: .atEntry(); iterator.next()) {
1015: ((PropertyMapImpl) iterator.getValue())
1016: .doCopy(
1017: (PropertyMapImpl) map
1018: .getChildMap((PropertyMapProperty) iterator
1019: .getKey()),
1020: copySuperMaps, recursive, false);
1021: }
1022: }
1023: }
1024: }
|