0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017:
0018: package java.beans.beancontext;
0019:
0020: import java.awt.Component;
0021: import java.beans.Beans;
0022: import java.beans.PropertyChangeEvent;
0023: import java.beans.PropertyChangeListener;
0024: import java.beans.PropertyVetoException;
0025: import java.beans.VetoableChangeListener;
0026: import java.beans.Visibility;
0027: import java.io.IOException;
0028: import java.io.InputStream;
0029: import java.io.ObjectInputStream;
0030: import java.io.ObjectOutputStream;
0031: import java.io.Serializable;
0032: import java.net.URL;
0033: import java.util.ArrayList;
0034: import java.util.Collection;
0035: import java.util.HashMap;
0036: import java.util.Iterator;
0037: import java.util.Locale;
0038:
0039: import org.apache.harmony.beans.internal.nls.Messages;
0040:
0041: /**
0042: * This support class implements <code>BeanContext</code> interface.
0043: * This class can be used directly, or be a super class of your class,
0044: * or be a delegate of your implementation that needs to support
0045: * <code>BeanContext</code> interface.
0046: *
0047: */
0048: public class BeanContextSupport extends BeanContextChildSupport
0049: implements BeanContext, PropertyChangeListener,
0050: VetoableChangeListener, Serializable {
0051:
0052: /**
0053: * Every child of context is companied with a <code>BCSChild</code>
0054: * instance. It can hold implementation specific information about
0055: * each child.
0056: * <p>
0057: * This class holds references of the child and its peer if there is one.</p>
0058: *
0059: */
0060: protected class BCSChild implements Serializable {
0061:
0062: static final long serialVersionUID = -5815286101609939109L;
0063:
0064: Object child;
0065:
0066: Object proxyPeer;
0067:
0068: BCSChild(Object child, Object proxyPeer) {
0069: this .child = child;
0070: this .proxyPeer = proxyPeer;
0071: }
0072: }
0073:
0074: /**
0075: * This implementation wraps an iterator and override
0076: * <code>remove()</code> with a noop method.
0077: *
0078: */
0079: protected static final class BCSIterator implements Iterator {
0080:
0081: private Iterator backIter;
0082:
0083: BCSIterator(Iterator backIter) {
0084: this .backIter = backIter;
0085: }
0086:
0087: public boolean hasNext() {
0088: return backIter.hasNext();
0089: }
0090:
0091: public Object next() {
0092: return backIter.next();
0093: }
0094:
0095: public void remove() {
0096: // no-op
0097: }
0098: }
0099:
0100: static final long serialVersionUID = -4879613978649577204L; //J2SE 1.4.2
0101:
0102: /**
0103: * A list of registered membership listeners.
0104: * All access to this object should be synchronized on itself.
0105: */
0106: @SuppressWarnings("unchecked")
0107: transient protected ArrayList bcmListeners;
0108:
0109: /**
0110: * A map of children - key is child instance, value is <code>BCSChild</code> instance.
0111: * All access to this object should be synchronized on itself.
0112: */
0113: @SuppressWarnings("unchecked")
0114: transient protected HashMap children;
0115:
0116: transient private boolean serializing;
0117:
0118: transient private boolean inNeedsGui;
0119:
0120: transient private PropertyChangeListener nonSerPCL;
0121:
0122: private int serializable;
0123:
0124: /**
0125: * The locale of this context.
0126: */
0127: protected Locale locale;
0128:
0129: /**
0130: * A flag indicating whether this context is allowed to use GUI.
0131: */
0132: protected boolean okToUseGui;
0133:
0134: /**
0135: * A flag indicating whether this context is in design mode.
0136: */
0137: protected boolean designTime;
0138:
0139: /**
0140: * Constructs a standload <code>BeanContextSupport</code>.
0141: */
0142: public BeanContextSupport() {
0143: this (null, Locale.getDefault(), false, true);
0144: }
0145:
0146: /**
0147: * Constructs a <code>BeanContextSupport</code> which is a delegate
0148: * of the given peer.
0149: *
0150: * @param peer the peer of this context
0151: */
0152: public BeanContextSupport(BeanContext peer) {
0153: this (peer, Locale.getDefault(), false, true);
0154: }
0155:
0156: /**
0157: * Constructs a <code>BeanContextSupport</code> which is a delegate
0158: * of the given peer.
0159: *
0160: * @param peer the peer of this context
0161: * @param locale the locale of this context
0162: */
0163: public BeanContextSupport(BeanContext peer, Locale locale) {
0164: this (peer, locale, false, true);
0165: }
0166:
0167: /**
0168: * Constructs a <code>BeanContextSupport</code> which is a delegate
0169: * of the given peer.
0170: *
0171: * @param peer the peer of this context
0172: * @param locale the locale of this context
0173: * @param designTime whether in design mode or not
0174: */
0175: public BeanContextSupport(BeanContext peer, Locale locale,
0176: boolean designTime) {
0177: this (peer, locale, designTime, true);
0178: }
0179:
0180: /**
0181: * Constructs a <code>BeanContextSupport</code> which is a delegate
0182: * of the given peer.
0183: *
0184: * @param peer the peer of this context
0185: * @param locale the locale of this context
0186: * @param designTime whether in design mode or not
0187: * @param okToUseGui whether GUI is usable or not
0188: */
0189: public BeanContextSupport(BeanContext peer, Locale locale,
0190: boolean designTime, boolean okToUseGui) {
0191: super (peer);
0192: if (locale == null) {
0193: locale = Locale.getDefault();
0194: }
0195: this .locale = locale;
0196: this .designTime = designTime;
0197: this .okToUseGui = okToUseGui;
0198:
0199: initialize();
0200: }
0201:
0202: /**
0203: * Add a child to this context.
0204: * <p>
0205: * If the child already exists in this context, simply returns false.
0206: * Otherwise, it is validated by calling <code>validatePendingAdd()</code>.
0207: * If the add is valid, the child and its proxy (if the child implements
0208: * <code>BeanContextProxy</code>) is then added, and <code>setBeanContext()</code>
0209: * is called on it (if the child implements <code>BeanContextChild</code>
0210: * or it has a proxy). Last, the <code>childJustAddedHook()</code> is
0211: * called and all registered <code>BeanContextMembershipListener</code>s
0212: * are notified.</p>
0213: *
0214: * @param child the child to add
0215: * @return true if the child is added to this context; otherwise false
0216: * @throws IllegalStateException if the child is not valid to add
0217: * @see java.util.Collection#add(java.lang.Object)
0218: */
0219: @SuppressWarnings("unchecked")
0220: public boolean add(Object child) {
0221: if (child == null) {
0222: throw new IllegalArgumentException("null child");
0223: }
0224:
0225: BeanContextChild proxy = null;
0226:
0227: synchronized (globalHierarchyLock) {
0228: // check existence
0229: if (contains(child)) {
0230: return false;
0231: }
0232:
0233: // check serializing state
0234: if (serializing) {
0235: throw new IllegalStateException(
0236: "cannot update children during serialization");
0237: }
0238:
0239: // validate
0240: boolean valid = validatePendingAdd(child);
0241: if (!valid) {
0242: throw new IllegalStateException(
0243: "Validation failed to add the child");
0244: }
0245:
0246: // find the proxy, if there's one
0247: if (child instanceof BeanContextProxy) {
0248: proxy = ((BeanContextProxy) child)
0249: .getBeanContextProxy();
0250: if (proxy == null) {
0251: throw new NullPointerException(
0252: "null BeanContextChild proxy");
0253: }
0254: }
0255: BeanContextChild beanContextChild = getChildBeanContextChild(child);
0256:
0257: // add to children
0258: BCSChild childBCSC = null, proxyBCSC = null;
0259: synchronized (children) {
0260: childBCSC = createBCSChild(child, proxy);
0261: children.put(child, childBCSC);
0262: if (proxy != null) {
0263: proxyBCSC = createBCSChild(proxy, child);
0264: children.put(proxy, proxyBCSC);
0265: }
0266: }
0267:
0268: // set child's beanContext property
0269: if (beanContextChild != null) {
0270: try {
0271: beanContextChild
0272: .setBeanContext(getBeanContextPeer());
0273: } catch (PropertyVetoException e) {
0274: synchronized (children) {
0275: children.remove(child);
0276: if (proxy != null) {
0277: children.remove(proxy);
0278: }
0279: }
0280: throw new IllegalStateException(
0281: "failed to update child's beanContext property");
0282: }
0283: // ensure no duplicate listener
0284: beanContextChild.removePropertyChangeListener(
0285: "beanContext", nonSerPCL);
0286: // listen to child's beanContext change
0287: beanContextChild.addPropertyChangeListener(
0288: "beanContext", nonSerPCL);
0289: }
0290:
0291: // trigger hook
0292: synchronized (child) {
0293: childJustAddedHook(child, childBCSC);
0294: }
0295: if (proxy != null) {
0296: synchronized (proxy) {
0297: childJustAddedHook(proxy, proxyBCSC);
0298: }
0299: }
0300: }
0301:
0302: // notify listeners
0303: fireChildrenAdded(new BeanContextMembershipEvent(
0304: getBeanContextPeer(),
0305: proxy == null ? new Object[] { child } : new Object[] {
0306: child, proxy }));
0307: return true;
0308: }
0309:
0310: /**
0311: * This method is unsupported, throws <code>UnsupportedOperationException</code>.
0312: *
0313: * @see java.util.Collection#addAll(java.util.Collection)
0314: */
0315: public boolean addAll(Collection collection) {
0316: throw new UnsupportedOperationException();
0317: }
0318:
0319: /* (non-Javadoc)
0320: * @see java.beans.beancontext.BeanContext#addBeanContextMembershipListener(java.beans.beancontext.BeanContextMembershipListener)
0321: */
0322: public void addBeanContextMembershipListener(
0323: BeanContextMembershipListener listener) {
0324: if (listener == null) {
0325: throw new NullPointerException();
0326: }
0327: synchronized (bcmListeners) {
0328: if (!bcmListeners.contains(listener)) {
0329: bcmListeners.add(listener);
0330: }
0331: }
0332: }
0333:
0334: /* (non-Javadoc)
0335: * @see java.beans.Visibility#avoidingGui()
0336: */
0337: public boolean avoidingGui() {
0338: // Avoiding GUI means that
0339: // GUI is needed but not allowed to use at this time
0340: return (needsGui() && !this .okToUseGui);
0341: }
0342:
0343: /**
0344: * Returns an iterator of all <code>BCSChild</code> instances,
0345: * with <code>remove()</code> disabled.
0346: *
0347: * @return an iterator of all <code>BCSChild</code> instances
0348: */
0349: protected Iterator bcsChildren() {
0350: synchronized (children) {
0351: return new BCSIterator(children.values().iterator());
0352: }
0353: }
0354:
0355: /**
0356: * This method is called by <code>readObject()</code> after
0357: * <code>defaultReadObject()</code> and before deserializing any
0358: * children or listeners. Subclass can insert its specific
0359: * deserialization behavior by overrideing this method.
0360: * <p>
0361: * The default implementation does nothing.</p>
0362: *
0363: * @param ois the object input stream
0364: * @throws IOException
0365: * @throws ClassNotFoundException
0366: */
0367: protected void bcsPreDeserializationHook(ObjectInputStream ois)
0368: throws IOException, ClassNotFoundException {
0369: // to be overridden
0370: }
0371:
0372: /**
0373: * This method is called by <code>writeObject()</code> after
0374: * <code>defaultWriteObject()</code> and before serializing any
0375: * children or listeners. Subclass can insert its specific
0376: * serialization behavior by overrideing this method.
0377: * <p>
0378: * The default implementation does nothing.</p>
0379: *
0380: * @param oos the object output stream
0381: * @throws IOException
0382: */
0383: protected void bcsPreSerializationHook(ObjectOutputStream oos)
0384: throws IOException {
0385: // to be overridden
0386: }
0387:
0388: /**
0389: * This method is called during deserialization everytime a child is read.
0390: * <p>
0391: * The default implementation does nothing.</p>
0392: *
0393: * @param child the child just deserialized
0394: * @param bcsChild the <code>BCSChild</code> just deserialized
0395: */
0396: protected void childDeserializedHook(Object child, BCSChild bcsChild) {
0397: // to be overridden
0398: }
0399:
0400: /**
0401: * This method is called everytime a child is added to this context.
0402: * This method is called with child synchronized.
0403: * <p>
0404: * The default implementation does nothing.</p>
0405: *
0406: * @param child the child just added
0407: * @param bcsChild the <code>BCSChild</code> just added
0408: */
0409: protected void childJustAddedHook(Object child, BCSChild bcsChild) {
0410: // to be overridden
0411: }
0412:
0413: /**
0414: * This method is called everytime a child is removed from this context.
0415: * This method is called with child synchronized.
0416: * <p>
0417: * The default implementation does nothing.</p>
0418: *
0419: * @param child the child just removed
0420: * @param bcsChild the <code>BCSChild</code> just removed
0421: */
0422: protected void childJustRemovedHook(Object child, BCSChild bcsChild) {
0423: // to be overridden
0424: }
0425:
0426: /**
0427: * Compares if two classes are equal or their class names are equal.
0428: *
0429: * @param clz1 a class
0430: * @param clz2 another class
0431: * @return true if two class objects are equal or their class names are equal.
0432: */
0433: protected static final boolean classEquals(Class clz1, Class clz2) {
0434: if (clz1 == null || clz2 == null) {
0435: throw new NullPointerException();
0436: }
0437: return clz1 == clz2 || clz1.getName().equals(clz2.getName());
0438: }
0439:
0440: /**
0441: * This method is unsupported, throws <code>UnsupportedOperationException</code>.
0442: *
0443: * @see java.util.Collection#clear()
0444: */
0445: public void clear() {
0446: throw new UnsupportedOperationException();
0447: }
0448:
0449: /**
0450: * Returns true if the given object is a child of this context.
0451: *
0452: * @param child the object to test
0453: * @return true if the given object is a child of this context
0454: * @see java.util.Collection#contains(java.lang.Object)
0455: */
0456: public boolean contains(Object child) {
0457: synchronized (children) {
0458: return children.containsKey(child);
0459: }
0460: }
0461:
0462: /**
0463: * Returns true if given objects are children of this context.
0464: *
0465: * @param collection a collection of objects
0466: * @return true if given objects are children of this context
0467: * @see java.util.Collection#containsAll(java.util.Collection)
0468: */
0469: @SuppressWarnings("unchecked")
0470: public boolean containsAll(Collection collection) {
0471: synchronized (children) {
0472: return children.keySet().containsAll(collection);
0473: }
0474: }
0475:
0476: /**
0477: * Returns true if the given object is a child of this context.
0478: *
0479: * @param child the object to test
0480: * @return true if the given object is a child of this context
0481: */
0482: public boolean containsKey(Object child) {
0483: synchronized (children) {
0484: return children.containsKey(child);
0485: }
0486: }
0487:
0488: /**
0489: * Returns an array containing all children of this context.
0490: *
0491: * @return an array containing all children of this context
0492: */
0493: protected final Object[] copyChildren() {
0494: synchronized (children) {
0495: return children.keySet().toArray();
0496: }
0497: }
0498:
0499: /**
0500: * Creates a <code>BCSChild</code> object to company the given child.
0501: *
0502: * @param child the child
0503: * @param proxyPeer the proxy peer of the child if there is one
0504: * @return a <code>BCSChild</code> object to company the given child
0505: */
0506: protected BCSChild createBCSChild(Object child, Object proxyPeer) {
0507: return new BCSChild(child, proxyPeer);
0508: }
0509:
0510: /**
0511: * Deserialize a collection.
0512: * <p>
0513: * First read a <code>int</code> indicating of number of rest objects,
0514: * then read the objects one by one.</p>
0515: *
0516: * @param ois the stream where the collection is read from
0517: * @param collection the collection to hold read objects
0518: * @throws IOException if I/O exception occurs
0519: * @throws ClassNotFoundException if class of any read object is not found
0520: */
0521: @SuppressWarnings("unchecked")
0522: protected final void deserialize(ObjectInputStream ois,
0523: Collection collection) throws IOException,
0524: ClassNotFoundException {
0525: int size = ois.readInt();
0526: for (int i = 0; i < size; i++) {
0527: collection.add(ois.readObject());
0528: }
0529: }
0530:
0531: /* (non-Javadoc)
0532: * @see java.beans.Visibility#dontUseGui()
0533: */
0534: public void dontUseGui() {
0535: okToUseGui = false;
0536: }
0537:
0538: /**
0539: * Notifies registered <code>BeanContextMembershipListener</code>s that
0540: * a new child has been added.
0541: *
0542: * @param event the <code>BeanContextMembershipEvent</code>
0543: */
0544: protected final void fireChildrenAdded(
0545: BeanContextMembershipEvent event) {
0546: Object listeners[];
0547: synchronized (bcmListeners) {
0548: listeners = bcmListeners.toArray();
0549: }
0550: for (int i = 0; i < listeners.length; i++) {
0551: BeanContextMembershipListener l = (BeanContextMembershipListener) listeners[i];
0552: l.childrenAdded(event);
0553: }
0554: }
0555:
0556: /**
0557: * Notifies registered <code>BeanContextMembershipListener</code>s that
0558: * a child has been removed.
0559: *
0560: * @param event the <code>BeanContextMembershipEvent</code>
0561: */
0562: protected final void fireChildrenRemoved(
0563: BeanContextMembershipEvent event) {
0564: Object listeners[];
0565: synchronized (bcmListeners) {
0566: listeners = bcmListeners.toArray();
0567: }
0568: for (int i = 0; i < listeners.length; i++) {
0569: BeanContextMembershipListener l = (BeanContextMembershipListener) listeners[i];
0570: l.childrenRemoved(event);
0571: }
0572: }
0573:
0574: /**
0575: * Returns the peer of this context casted as <code>BeanContext</code>.
0576: *
0577: * @return the peer of this context casted as <code>BeanContext</code>
0578: */
0579: public BeanContext getBeanContextPeer() {
0580: return (BeanContext) beanContextChildPeer;
0581: }
0582:
0583: /**
0584: * Returns the <code>BeanContextChild</code> related with the given child.
0585: * <p>
0586: * If the child implements <code>BeanContextChild</code>, it is returned.
0587: * If the child implements <code>BeanContextProxy</code>, the proxy is returned.
0588: * Otherwise, null is returned.</p>
0589: *
0590: * @param child a child
0591: * @return the <code>BeanContextChild</code> related with the given child
0592: * @throws IllegalStateException if the child implements both <code>BeanContextChild</code> and <code>BeanContextProxy</code>
0593: */
0594: protected static final BeanContextChild getChildBeanContextChild(
0595: Object child) {
0596: if (child instanceof BeanContextChild) {
0597: if (child instanceof BeanContextProxy) {
0598: throw new IllegalArgumentException(
0599: "Illegal to impl both BeanContextChild and BeanContextProxy");
0600: }
0601: return (BeanContextChild) child;
0602: }
0603: if (child instanceof BeanContextProxy) {
0604: if (child instanceof BeanContextChild) {
0605: throw new IllegalArgumentException(
0606: "Illegal to impl both BeanContextChild and BeanContextProxy");
0607: }
0608: return ((BeanContextProxy) child).getBeanContextProxy();
0609: }
0610: return null;
0611: }
0612:
0613: /**
0614: * Returns the given child casted to <code>BeanContextMembershipListener</code>,
0615: * or null if it does not implements the interface.
0616: *
0617: * @param child a child
0618: * @return the given child casted to <code>BeanContextMembershipListener</code>,
0619: * or null if it does not implements the interface
0620: */
0621: protected static final BeanContextMembershipListener getChildBeanContextMembershipListener(
0622: Object child) {
0623: if (child instanceof BeanContextMembershipListener) {
0624: return (BeanContextMembershipListener) child;
0625: } else {
0626: return null;
0627: }
0628: }
0629:
0630: /**
0631: * Returns the given child casted to <code>PropertyChangeListener</code>,
0632: * or null if it does not implements the interface.
0633: *
0634: * @param child a child
0635: * @return the given child casted to <code>PropertyChangeListener</code>,
0636: * or null if it does not implements the interface
0637: */
0638: protected static final PropertyChangeListener getChildPropertyChangeListener(
0639: Object child) {
0640: if (child instanceof PropertyChangeListener) {
0641: return (PropertyChangeListener) child;
0642: } else {
0643: return null;
0644: }
0645: }
0646:
0647: /**
0648: * Returns the given child casted to <code>Serializable</code>,
0649: * or null if it does not implements the interface.
0650: *
0651: * @param child a child
0652: * @return the given child casted to <code>Serializable</code>,
0653: * or null if it does not implements the interface
0654: */
0655: protected static final Serializable getChildSerializable(
0656: Object child) {
0657: if (child instanceof Serializable) {
0658: return (Serializable) child;
0659: } else {
0660: return null;
0661: }
0662: }
0663:
0664: /**
0665: * Returns the given child casted to <code>VetoableChangeListener</code>,
0666: * or null if it does not implements the interface.
0667: *
0668: * @param child a child
0669: * @return the given child casted to <code>VetoableChangeListener</code>,
0670: * or null if it does not implements the interface
0671: */
0672: protected static final VetoableChangeListener getChildVetoableChangeListener(
0673: Object child) {
0674: if (child instanceof VetoableChangeListener) {
0675: return (VetoableChangeListener) child;
0676: } else {
0677: return null;
0678: }
0679: }
0680:
0681: /**
0682: * Returns the given child casted to <code>Visibility</code>,
0683: * or null if it does not implements the interface.
0684: *
0685: * @param child a child
0686: * @return the given child casted to <code>Visibility</code>,
0687: * or null if it does not implements the interface
0688: */
0689: protected static final Visibility getChildVisibility(Object child) {
0690: if (child instanceof Visibility) {
0691: return (Visibility) child;
0692: } else {
0693: return null;
0694: }
0695: }
0696:
0697: /**
0698: * Returns the locale of this context.
0699: *
0700: * @return the locale of this context
0701: */
0702: public Locale getLocale() {
0703: return locale;
0704: }
0705:
0706: /* (non-Javadoc)
0707: * @see java.beans.beancontext.BeanContext#getResource(java.lang.String, java.beans.beancontext.BeanContextChild)
0708: */
0709: public URL getResource(String resourceName, BeanContextChild child) {
0710: if (resourceName == null || child == null) {
0711: throw new NullPointerException();
0712: }
0713: if (!contains(child)) {
0714: throw new IllegalArgumentException(
0715: "Not a child of this context");
0716: }
0717:
0718: return ClassLoader.getSystemResource(resourceName);
0719: }
0720:
0721: /* (non-Javadoc)
0722: * @see java.beans.beancontext.BeanContext#getResourceAsStream(java.lang.String, java.beans.beancontext.BeanContextChild)
0723: */
0724: public InputStream getResourceAsStream(String resourceName,
0725: BeanContextChild child) throws IllegalArgumentException {
0726: if (resourceName == null || child == null) {
0727: throw new NullPointerException();
0728: }
0729: if (!contains(child)) {
0730: throw new IllegalArgumentException(
0731: "Not a child of this context");
0732: }
0733:
0734: return ClassLoader.getSystemResourceAsStream(resourceName);
0735: }
0736:
0737: /**
0738: * Initializes all transient fields of this instance, called by
0739: * constructors and <code>readObject()</code>.
0740: */
0741: protected void initialize() {
0742: // init transient fields
0743: bcmListeners = new ArrayList<BeanContextMembershipListener>();
0744: children = new HashMap();
0745: serializing = false;
0746: inNeedsGui = false;
0747: nonSerPCL = new PropertyChangeListener() {
0748: public void propertyChange(PropertyChangeEvent event) {
0749: BeanContextSupport.this .propertyChange(event);
0750: }
0751: };
0752: }
0753:
0754: /* (non-Javadoc)
0755: * @see java.beans.beancontext.BeanContext#instantiateChild(java.lang.String)
0756: */
0757: public Object instantiateChild(String beanName) throws IOException,
0758: ClassNotFoundException {
0759: return Beans.instantiate(getClass().getClassLoader(), beanName,
0760: getBeanContextPeer());
0761: }
0762:
0763: /* (non-Javadoc)
0764: * @see java.beans.DesignMode#isDesignTime()
0765: */
0766: public boolean isDesignTime() {
0767: return designTime;
0768: }
0769:
0770: /* (non-Javadoc)
0771: * @see java.util.Collection#isEmpty()
0772: */
0773: public boolean isEmpty() {
0774: synchronized (children) {
0775: return children.isEmpty();
0776: }
0777: }
0778:
0779: /**
0780: * Returns true if this context is currently being serialized
0781: * (by another thread).
0782: *
0783: * @return true if this context is currently being serialized
0784: * (by another thread)
0785: */
0786: public boolean isSerializing() {
0787: return serializing;
0788: }
0789:
0790: /**
0791: * Returns an iterator of children of this context,
0792: * with <code>remove()</code> disabled.
0793: *
0794: * @see java.util.Collection#iterator()
0795: */
0796: public Iterator iterator() {
0797: synchronized (children) {
0798: return new BCSIterator(children.keySet().iterator());
0799: }
0800: }
0801:
0802: /**
0803: * Returns true if this context or its children needs GUI to work properly.
0804: * <p>
0805: * The implementation checks the peer and all the children that implement
0806: * <code>Visibility</code> to see if any of their <code>needsGui()</code>
0807: * returns true, and if any of the children extends
0808: * <code>java.awt.Component</code>.</p>
0809: *
0810: * @see java.beans.Visibility#needsGui()
0811: */
0812: public boolean needsGui() {
0813: if (inNeedsGui) {
0814: return false;
0815: }
0816: inNeedsGui = true;
0817:
0818: try {
0819: if (getBeanContextPeer() != this ) {
0820: if (getBeanContextPeer().needsGui()) {
0821: return true;
0822: }
0823: }
0824: Object childs[] = copyChildren();
0825: for (int i = 0; i < childs.length; i++) {
0826: if (childs[i] instanceof Component) {
0827: return true;
0828: }
0829: Visibility v = getChildVisibility(childs[i]);
0830: if (v != null && v.needsGui()) {
0831: return true;
0832: }
0833: }
0834: return false;
0835: } finally {
0836: inNeedsGui = false;
0837: }
0838: }
0839:
0840: /* (non-Javadoc)
0841: * @see java.beans.Visibility#okToUseGui()
0842: */
0843: public void okToUseGui() {
0844: okToUseGui = true;
0845: }
0846:
0847: /* (non-Javadoc)
0848: * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
0849: */
0850: public void propertyChange(PropertyChangeEvent event) {
0851: if (contains(event.getSource())
0852: && "beanContext".equals(event.getPropertyName())
0853: && event.getOldValue() == getBeanContextPeer()) {
0854: remove(event.getSource(), false);
0855: }
0856: }
0857:
0858: /**
0859: * Deserializes children from the given object input stream.
0860: * <p>
0861: * The implementation reads pairs of child object and <code>BCSChild</code>
0862: * object according to <code>serializable</code> property. For each pair,
0863: * it is added to the <code>children</code> map and the
0864: * <code>childDeserializedHook()</code> is called. If the child implements
0865: * <code>BeanContextChild</code>, its <code>setBeanContext()</code> is
0866: * also called.
0867: * </p>
0868: * <p>
0869: * This method is called by <code>readObject()</code> if the context works
0870: * standalone. Or if this support object is a delegate of another
0871: * <code>BeanContext</code> implementation, then this method should be
0872: * called by the peer. Doing this means that derialization can proceed
0873: * without any circular dependency problems.
0874: *
0875: * @param ois
0876: * the object input stream
0877: * @throws IOException
0878: * if I/O exception occurs
0879: * @throws ClassNotFoundException
0880: * if class of read object is not found
0881: */
0882: @SuppressWarnings("unchecked")
0883: public final void readChildren(ObjectInputStream ois)
0884: throws IOException, ClassNotFoundException {
0885: synchronized (children) {
0886: for (int i = 0; i < serializable; i++) {
0887: Object child = ois.readObject();
0888: BCSChild childBCSC = (BCSChild) ois.readObject();
0889: children.put(child, childBCSC);
0890:
0891: childDeserializedHook(child, childBCSC);
0892:
0893: // set child's beanContext property
0894: BeanContextChild beanContextChild = getChildBeanContextChild(child);
0895: if (beanContextChild != null) {
0896: try {
0897: beanContextChild
0898: .setBeanContext(getBeanContextPeer());
0899: } catch (PropertyVetoException e) {
0900: throw new IOException(
0901: "failed to update child's beanContext property");
0902: }
0903: // ensure no duplicate listener
0904: beanContextChild.removePropertyChangeListener(
0905: "beanContext", nonSerPCL);
0906: // listen to child's beanContext change
0907: beanContextChild.addPropertyChangeListener(
0908: "beanContext", nonSerPCL);
0909: }
0910: }
0911: }
0912: }
0913:
0914: /**
0915: * Removes the given child from this context.
0916: * <p>
0917: * Delegates to <code>remove(child, true)</code>.</p>
0918: *
0919: * @param child a child of this context
0920: * @return true if the child is removed; or false if it is not a child of this context
0921: * @throws IllegalArgumentException if the child is null
0922: * @throws IllegalStateException if the child is not valid to remove
0923: * @see java.util.Collection#remove(java.lang.Object)
0924: */
0925: public boolean remove(Object child) {
0926: return remove(child, true);
0927: }
0928:
0929: /**
0930: * Removes the given child from this context.
0931: * <p>
0932: * If the given child is not a child of this context, simply returns false.
0933: * Otherwise, <code>validatePendingRemove()</code> is called. If the
0934: * removal is valid, the child's <code>beanContext</code> property is
0935: * updated (if required) and the child and its proxy peer (if there is one)
0936: * is removed. Last, <code>childJustRemovedHook()</code> is called and
0937: * listeners are notified.</p>
0938: *
0939: * @param child a child of this context
0940: * @param setChildBC whether to call <code>setBeanContext()</code> on the child or not
0941: * @return true if the child is removed; or false if it is not a child of this context
0942: * @throws IllegalArgumentException if the child is null
0943: * @throws IllegalStateException if the child is not valid to remove
0944: */
0945: protected boolean remove(Object child, boolean setChildBC) {
0946: if (child == null) {
0947: throw new IllegalArgumentException("null child");
0948: }
0949:
0950: Object peer = null;
0951:
0952: synchronized (globalHierarchyLock) {
0953: // check existence
0954: if (!contains(child)) {
0955: return false;
0956: }
0957:
0958: // check serializing state
0959: if (serializing) {
0960: throw new IllegalStateException(
0961: "cannot update children during serialization");
0962: }
0963:
0964: // validate
0965: boolean valid = validatePendingRemove(child);
0966: if (!valid) {
0967: throw new IllegalStateException(
0968: "Validation failed to remove the child");
0969: }
0970:
0971: // set child's beanContext property
0972: BeanContextChild beanContextChild = getChildBeanContextChild(child);
0973: if (beanContextChild != null && setChildBC) {
0974: // remove listener, first
0975: beanContextChild.removePropertyChangeListener(
0976: "beanContext", nonSerPCL);
0977: try {
0978: beanContextChild.setBeanContext(null);
0979: } catch (PropertyVetoException e) {
0980: // rollback the listener change
0981: beanContextChild.addPropertyChangeListener(
0982: "beanContext", nonSerPCL);
0983: throw new IllegalStateException(
0984: "failed to update child's beanContext property");
0985: }
0986: }
0987:
0988: // remove from children
0989: BCSChild childBCSC = null, peerBCSC = null;
0990: synchronized (children) {
0991: childBCSC = (BCSChild) children.remove(child);
0992: peer = childBCSC.proxyPeer;
0993: if (peer != null) {
0994: peerBCSC = (BCSChild) children.remove(peer);
0995: }
0996: }
0997:
0998: // trigger hook
0999: synchronized (child) {
1000: childJustRemovedHook(child, childBCSC);
1001: }
1002: if (peer != null) {
1003: synchronized (peer) {
1004: childJustRemovedHook(peer, peerBCSC);
1005: }
1006: }
1007: }
1008:
1009: // notify listeners
1010: fireChildrenRemoved(new BeanContextMembershipEvent(
1011: getBeanContextPeer(),
1012: peer == null ? new Object[] { child } : new Object[] {
1013: child, peer }));
1014: return true;
1015: }
1016:
1017: /**
1018: * This method is unsupported, throws <code>UnsupportedOperationException</code>.
1019: *
1020: * @see java.util.Collection#removeAll(java.util.Collection)
1021: */
1022: public boolean removeAll(Collection collection) {
1023: throw new UnsupportedOperationException();
1024: }
1025:
1026: /* (non-Javadoc)
1027: * @see java.beans.beancontext.BeanContext#removeBeanContextMembershipListener(java.beans.beancontext.BeanContextMembershipListener)
1028: */
1029: public void removeBeanContextMembershipListener(
1030: BeanContextMembershipListener listener) {
1031: if (listener == null) {
1032: throw new NullPointerException();
1033: }
1034: synchronized (bcmListeners) {
1035: bcmListeners.remove(listener);
1036: }
1037: }
1038:
1039: /**
1040: * This method is unsupported, throws <code>UnsupportedOperationException</code>.
1041: *
1042: * @see java.util.Collection#retainAll(java.util.Collection)
1043: */
1044: public boolean retainAll(Collection collection) {
1045: throw new UnsupportedOperationException();
1046: }
1047:
1048: /**
1049: * Serializes the given collection.
1050: * <p>
1051: * First writes a <code>int</code> indicating the number of all
1052: * serializable elements (implements <code>Serializable</code>, then
1053: * objects are writtern one by one.</p>
1054: *
1055: * @param oos the stream where the collection is writtern to
1056: * @param collection the collection to serialize
1057: * @throws IOException if I/O exception occurs
1058: */
1059: protected final void serialize(ObjectOutputStream oos,
1060: Collection collection) throws IOException {
1061: Object array[] = collection.toArray();
1062: int serCount = 0;
1063: for (int i = 0; i < array.length; i++) {
1064: if (array[i] instanceof Serializable) {
1065: serCount++;
1066: }
1067: }
1068:
1069: oos.writeInt(serCount);
1070: for (int i = 0; i < array.length; i++) {
1071: if (array[i] instanceof Serializable) {
1072: oos.writeObject(array[i]);
1073: }
1074: }
1075: }
1076:
1077: /* (non-Javadoc)
1078: * @see java.beans.DesignMode#setDesignTime(boolean)
1079: */
1080: public void setDesignTime(boolean designTime) {
1081: this .designTime = designTime;
1082: }
1083:
1084: /**
1085: * Sets the locale of this context. <code>VetoableChangeListener</code>s
1086: * and <code>PropertyChangeListener</code>s are notified.
1087: *
1088: * @param newLocale the new locale to set
1089: * @throws PropertyVetoException if any <code>VetoableChangeListener</code> vetos this change
1090: */
1091: public void setLocale(Locale newLocale)
1092: throws PropertyVetoException {
1093: if (newLocale == null || newLocale == locale) {
1094: return; // ignore null locale
1095: }
1096:
1097: PropertyChangeEvent event = new PropertyChangeEvent(
1098: beanContextChildPeer, "locale", locale, newLocale);
1099:
1100: // apply change
1101: Locale oldLocale = locale;
1102: locale = newLocale;
1103:
1104: try {
1105: // notify vetoable listeners
1106: vcSupport.fireVetoableChange(event);
1107: } catch (PropertyVetoException e) {
1108: // rollback change
1109: locale = oldLocale;
1110: throw e;
1111: }
1112: // Notify BeanContext about this change
1113: this .pcSupport.firePropertyChange(event);
1114: }
1115:
1116: /**
1117: * Returns the number children of this context.
1118: *
1119: * @return the number children of this context
1120: * @see java.util.Collection#size()
1121: */
1122: public int size() {
1123: synchronized (children) {
1124: return children.size();
1125: }
1126: }
1127:
1128: /**
1129: * Returns an array of children of this context.
1130: *
1131: * @return an array of children of this context
1132: * @see java.util.Collection#toArray()
1133: */
1134: public Object[] toArray() {
1135: synchronized (children) {
1136: return children.keySet().toArray();
1137: }
1138: }
1139:
1140: /**
1141: * Returns an array of children of this context.
1142: *
1143: * @return an array of children of this context
1144: * @see java.util.Collection#toArray(java.lang.Object[])
1145: */
1146: @SuppressWarnings("unchecked")
1147: public Object[] toArray(Object[] array) {
1148: synchronized (children) {
1149: return children.keySet().toArray(array);
1150: }
1151: }
1152:
1153: /**
1154: * Validates the pending add of child.
1155: * <p>
1156: * Default implementation always returns true.</p>
1157: *
1158: * @param child the child to be added
1159: * @return true if it is valid to add the child
1160: */
1161: protected boolean validatePendingAdd(Object child) {
1162: // to be overridden
1163: return true;
1164: }
1165:
1166: /**
1167: * Validates the pending removal of child.
1168: * <p>
1169: * Default implementation always returns true.</p>
1170: *
1171: * @param child the child to be removed
1172: * @return true if it is valid to remove the child
1173: */
1174: protected boolean validatePendingRemove(Object child) {
1175: // to be overridden
1176: return true;
1177: }
1178:
1179: /* (non-Javadoc)
1180: * @see java.beans.VetoableChangeListener#vetoableChange(java.beans.PropertyChangeEvent)
1181: */
1182: public void vetoableChange(PropertyChangeEvent pce)
1183: throws PropertyVetoException {
1184: if (pce == null) {
1185: throw new NullPointerException(Messages
1186: .getString("beans.1C")); //$NON-NLS-1$
1187: }
1188: }
1189:
1190: /**
1191: * Serializes children to the given object input stream.
1192: * <p>
1193: * The implementation iterates through all children and writes out pairs
1194: * of child object and <code>BCSChild</code> object if the child is
1195: * serializable (implements <code>Serialization</code>.</p>
1196: * <p>
1197: * This method is called by <code>writeObject()</code> if the context
1198: * works standalone. Or if this support object is a delegate of another
1199: * <code>BeanContext</code> implementation, then this method should be
1200: * called by the peer to avoid the 'chicken and egg' problem during
1201: * deserialization.</p>
1202: *
1203: * @param oos the stream to write
1204: * @throws IOException if I/O exception occurs
1205: */
1206: public final void writeChildren(ObjectOutputStream oos)
1207: throws IOException {
1208: boolean origSer = serializing;
1209: serializing = true;
1210:
1211: try {
1212: int count = 0;
1213: synchronized (children) {
1214: for (Iterator iter = children.values().iterator(); iter
1215: .hasNext();) {
1216: BCSChild bcsc = (BCSChild) iter.next();
1217: if (bcsc.child instanceof Serializable
1218: && (bcsc.proxyPeer == null || bcsc.proxyPeer instanceof Serializable)) {
1219: oos.writeObject(bcsc.child);
1220: oos.writeObject(bcsc);
1221: count++;
1222: }
1223: }
1224: }
1225:
1226: // what if count not equals to serializable?
1227: if (count != serializable) {
1228: throw new IOException(
1229: "children changed during serialization!");
1230: }
1231: } finally {
1232: serializing = origSer;
1233: }
1234: }
1235:
1236: /**
1237: * The implementation goes through following steps:
1238: * <p>
1239: * <ol>
1240: * <li>Writes out non-transient properties by calling
1241: * <code>defaultWriteObject()</code>, especially the
1242: * <code>serializable</code> indicating the number of serializable
1243: * children.</li>
1244: * <li>Calls <code>bcsPreSerializationHook()</code>.</li>
1245: * <li>Writes out children by calling <code>writeChildren()</code> if
1246: * this context works standalone. Otherwise it is the peer's
1247: * responsibility to call <code>writeChildren()</code> after this object
1248: * is serialized.</li>
1249: * <li>Writes out serializable membership listeners.</li>
1250: * </ol>
1251: * </p>
1252: *
1253: * @param oos the object output stream
1254: * @throws IOException if I/O exception occurs
1255: */
1256: private void writeObject(ObjectOutputStream oos) throws IOException {
1257: boolean origSer = serializing;
1258: serializing = true;
1259:
1260: try {
1261: // count serializable children
1262: synchronized (children) {
1263: serializable = 0;
1264: for (Iterator iter = children.values().iterator(); iter
1265: .hasNext();) {
1266: BCSChild bcsc = (BCSChild) iter.next();
1267: if (bcsc.child instanceof Serializable
1268: && (bcsc.proxyPeer == null || bcsc.proxyPeer instanceof Serializable)) {
1269: serializable++;
1270: }
1271: }
1272: }
1273:
1274: oos.defaultWriteObject();
1275:
1276: bcsPreSerializationHook(oos);
1277:
1278: if (this == getBeanContextPeer()) {
1279: writeChildren(oos);
1280: }
1281:
1282: synchronized (bcmListeners) {
1283: serialize(oos, bcmListeners);
1284: }
1285: } finally {
1286: serializing = origSer;
1287: }
1288: }
1289:
1290: /**
1291: * The implementation goes through following steps:
1292: * <p>
1293: * <ol>
1294: * <li>Reads non-transient properties by calling
1295: * <code>defaultReadObject()</code>.</li>
1296: * <li>Calls <code>bcsPreDeserializationHook()</code>.</li>
1297: * <li>Reads children by calling <code>readChildren()</code> if
1298: * this context works standalone. Otherwise it is the peer's
1299: * responsibility to call <code>readChildren()</code> after this object
1300: * is deserialized.</li>
1301: * <li>Reads serializable membership listeners.</li>
1302: * </ol>
1303: * </p>
1304: *
1305: * @param ois the object input stream
1306: * @throws IOException if I/O error occurs
1307: * @throws ClassNotFoundException if class of read object is not found
1308: */
1309: private void readObject(ObjectInputStream ois) throws IOException,
1310: ClassNotFoundException {
1311:
1312: ois.defaultReadObject();
1313:
1314: initialize(); // init transient fields
1315:
1316: bcsPreDeserializationHook(ois);
1317:
1318: if (this == getBeanContextPeer()) {
1319: readChildren(ois);
1320: }
1321:
1322: synchronized (bcmListeners) {
1323: deserialize(ois, bcmListeners);
1324: }
1325: }
1326:
1327: }
|