/**
   * Returns an array of all the listeners that were added to the PropertyChangeSupport object with
   * addPropertyChangeListener().
   *
   * <p>If some listeners have been added with a named property, then the returned array will be a
   * mixture of PropertyChangeListeners and <code>PropertyChangeListenerProxy</code>s. If the
   * calling method is interested in distinguishing the listeners then it must test each element to
   * see if it's a <code>PropertyChangeListenerProxy</code>, perform the cast, and examine the
   * parameter.
   *
   * <pre>
   * PropertyChangeListener[] listeners = bean.getPropertyChangeListeners();
   * for (int i = 0; i < listeners.length; i++) {
   *  if (listeners[i] instanceof PropertyChangeListenerProxy) {
   *     PropertyChangeListenerProxy proxy =
   *                    (PropertyChangeListenerProxy)listeners[i];
   *     if (proxy.getPropertyName().equals("foo")) {
   *       // proxy is a PropertyChangeListener which was associated
   *       // with the property named "foo"
   *     }
   *   }
   * }
   * </pre>
   *
   * @see PropertyChangeListenerProxy
   * @return all of the <code>PropertyChangeListeners</code> added or an empty array if no listeners
   *     have been added
   * @since 1.4
   */
  public synchronized PropertyChangeListener[] getPropertyChangeListeners() {
    List returnList = new ArrayList();

    // Add all the PropertyChangeListeners
    if (listeners != null) {
      returnList.addAll(Arrays.asList(listeners.getListenersInternal()));
    }

    // Add all the PropertyChangeListenerProxys
    if (children != null) {
      Iterator iterator = children.keySet().iterator();
      while (iterator.hasNext()) {
        String key = (String) iterator.next();
        PropertyChangeSupport child = (PropertyChangeSupport) children.get(key);
        PropertyChangeListener[] childListeners = child.getPropertyChangeListeners();
        for (int index = childListeners.length - 1; index >= 0; index--) {
          returnList.add(new PropertyChangeListenerProxy(key, childListeners[index]));
        }
      }
    }
    return (PropertyChangeListener[]) (returnList.toArray(new PropertyChangeListener[0]));
  }
  /**
   * Fire an existing PropertyChangeEvent to any registered listeners. No event is fired if the
   * given event's old and new values are equal and non-null.
   *
   * @param evt The PropertyChangeEvent object.
   */
  public void firePropertyChange(PropertyChangeEvent evt) {
    Object oldValue = evt.getOldValue();
    Object newValue = evt.getNewValue();
    String propertyName = evt.getPropertyName();
    if (oldValue != null && newValue != null && oldValue.equals(newValue)) {
      return;
    }

    if (listeners != null) {
      Object[] list = listeners.getListenersInternal();
      for (int i = 0; i < list.length; i++) {
        PropertyChangeListener target = (PropertyChangeListener) list[i];
        target.propertyChange(evt);
      }
    }

    if (children != null && propertyName != null) {
      PropertyChangeSupport child = null;
      child = (PropertyChangeSupport) children.get(propertyName);
      if (child != null) {
        child.firePropertyChange(evt);
      }
    }
  }