@Override
  public Proxy<?>[] releaseProxy(boolean destroy) {
    if (connectionStateMachine.isConnected()) {
      setConnectionState(ConnectionState.DISCONNECTING, null);
    }

    if (this.proxy != null) {
      this.proxy.removeProxyListener(proxyListener);
      if (this.directoryProxy != null && this.directoryProxy != this.proxy) {
        this.directoryProxy.removeProxyListener(proxyListener);
      }
    }
    Proxy<?>[] p = super.releaseProxy(destroy);
    if (connectionStateMachine.getConnectionState() == ConnectionState.DISCONNECTING) {
      setConnectionState(ConnectionState.DISCONNECTED, null);
    }

    if (destroy) {
      setConnectionState(ConnectionState.DESTROYED, null);
      linkListeners.clear();
      responseListeners.clear();
    }

    return p;
  }
  /**
   * Notifies all the <code>GroupListener<code> objects, about members added/removed.
   *
   * @param event Group event
   * @param added <code>true</code> if members were added, <code>false</code> otherwise.
   */
  protected void fireGroupEvent(DeviceGroupEvent<T> event, boolean added) {
    if (groupListeners == null) {
      return;
    }

    DeviceGroupListener<T>[] l = (DeviceGroupListener<T>[]) groupListeners.toArray();

    if (added) {
      for (int i = 0; i < l.length; i++) {
        try {
          l[i].membersAdded(event);
        } catch (Exception e) {
          Logger.getLogger(DeviceCollectionMap.class)
              .warn("Error in event handler, continuing.", e);
        }
      }
    } else {
      for (int i = 0; i < l.length; i++) {
        try {
          l[i].membersRemoved(event);
        } catch (Exception e) {
          Logger.getLogger(DeviceCollectionMap.class)
              .warn("Error in event handler, continuing.", e);
        }
      }
    }
  }
  /* (non-Javadoc)
   * @see org.csstudio.dal.group.DeviceCollection#getGroupListners()
   */
  public DeviceGroupListener<T>[] getDeviceGroupListners() {
    if (groupListeners != null) {
      return (DeviceGroupListener<T>[]) groupListeners.toArray();
    }

    return new DeviceGroupListener[0];
  }
  /* (non-Javadoc)
   * @see org.csstudio.dal.group.DeviceCollection#addGroupListner(org.csstudio.dal.group.GroupListener)
   */
  public void addDeviceGroupListner(DeviceGroupListener<T> l) {
    if (groupListeners == null) {
      groupListeners = new ListenerList(DeviceGroupListener.class);
    }

    groupListeners.add(l);
  }
  protected void fireResponseError(ResponseEvent event) {
    lastResponse = event.getResponse();

    Iterator<ResponseListener<?>> ite = responseListeners.iterator();

    while (ite.hasNext()) {
      ite.next().responseError(event);
    }
  }
  /* (non-Javadoc)
   * @see org.csstudio.dal.context.Linkable#addLinkListener(org.csstudio.dal.context.LinkListener)
   */
  public void addLinkListener(LinkListener<? extends Linkable> l) {
    linkListeners.add(l);
    if (lastConnectionEvent != null && l != null) {
      ConnectionEvent e = lastConnectionEvent;
      ConnectionState connectionState = e.getState();

      if (connectionState == ConnectionState.CONNECTED) {
        try {
          l.connected(e);
        } catch (Exception ex) {
          Logger.getLogger(DynamicValuePropertyImpl.class)
              .warn("Exception in event handler, continuing.", ex);
        }
      } else if (connectionState == ConnectionState.CONNECTION_FAILED) {
        try {
          l.connectionFailed(e);
        } catch (Exception ex) {
          Logger.getLogger(DynamicValuePropertyImpl.class)
              .warn("Exception in event handler, continuing.", ex);
        }
      } else if (connectionState == ConnectionState.CONNECTION_LOST) {
        try {
          l.connectionLost(e);
        } catch (Exception ex) {
          Logger.getLogger(DynamicValuePropertyImpl.class)
              .warn("Exception in event handler, continuing.", ex);
        }
      } else if (connectionState == ConnectionState.DISCONNECTED) {
        try {
          l.disconnected(e);
        } catch (Exception ex) {
          Logger.getLogger(DynamicValuePropertyImpl.class)
              .warn("Exception in event handler, continuing.", ex);
        }
      } else if (connectionState == ConnectionState.DESTROYED) {
        try {
          l.destroyed(e);
        } catch (Exception ex) {
          Logger.getLogger(DynamicValuePropertyImpl.class)
              .warn("Exception in event handler, continuing.", ex);
        }
      } else if (connectionState == ConnectionState.OPERATIONAL) {
        try {
          l.operational(e);
        } catch (Exception ex) {
          Logger.getLogger(DynamicValuePropertyImpl.class)
              .warn("Exception in event handler, continuing.", ex);
        }
      }
    }
  }
 /* (non-Javadoc)
  * @see org.csstudio.dal.group.DeviceCollection#removeGroupListner(org.csstudio.dal.group.GroupListener)
  */
 public void removeDeviceGroupListner(DeviceGroupListener<T> l) {
   if (groupListeners != null) {
     groupListeners.remove(l);
   }
 }
  /** @param connectionState The connectionState to set. */
  protected void setConnectionState(ConnectionState connectionState, Throwable error) {
    boolean change = false;

    try {
      change = connectionStateMachine.requestNextConnectionState(connectionState);
    } catch (IllegalStateException e) {
      Logger.getLogger(this.getClass()).error("Internal error.", e);
      throw e;
    }

    if (!change) {
      return;
    }

    LinkListener<Linkable>[] l = (LinkListener<Linkable>[]) linkListeners.toArray();

    ConnectionEvent<Linkable> e = new ConnectionEvent<Linkable>(this, connectionState, error);
    lastConnectionEvent = e;

    if (connectionState == ConnectionState.CONNECTED) {

      if (hasDynamicValueListeners() && defaultMonitor == null) {
        getDefaultMonitor();
      }

      for (MonitorProxyWrapper<T, ? extends SimpleProperty<T>> mpw : monitors) {
        if (!mpw.isInitialized()) {
          try {
            MonitorProxy mp = proxy.createMonitor(mpw, mpw.getInitialParameters());
            mpw.initialize(mp);
          } catch (RemoteException e1) {
            // TODO mark mpw for removal from monitors?
            // if yes, it has to be done outside loop
          }
        }
      }

      for (int i = 0; i < l.length; i++) {
        try {
          l[i].connected(e);
        } catch (Exception ex) {
          Logger.getLogger(DynamicValuePropertyImpl.class)
              .warn("Exception in event handler, continuing.", ex);
        }
      }
    } else if (connectionState == ConnectionState.CONNECTION_FAILED) {
      for (int i = 0; i < l.length; i++) {
        try {
          l[i].connectionFailed(e);
        } catch (Exception ex) {
          Logger.getLogger(DynamicValuePropertyImpl.class)
              .warn("Exception in event handler, continuing.", ex);
        }
      }
    } else if (connectionState == ConnectionState.CONNECTION_LOST) {
      for (int i = 0; i < l.length; i++) {
        try {
          l[i].connectionLost(e);
        } catch (Exception ex) {
          Logger.getLogger(DynamicValuePropertyImpl.class)
              .warn("Exception in event handler, continuing.", ex);
        }
      }
    } else if (connectionState == ConnectionState.DISCONNECTED) {
      for (int i = 0; i < l.length; i++) {
        try {
          l[i].disconnected(e);
        } catch (Exception ex) {
          Logger.getLogger(DynamicValuePropertyImpl.class)
              .warn("Exception in event handler, continuing.", ex);
        }
      }
    } else if (connectionState == ConnectionState.DESTROYED) {
      for (int i = 0; i < l.length; i++) {
        try {
          l[i].destroyed(e);
        } catch (Exception ex) {
          Logger.getLogger(DynamicValuePropertyImpl.class)
              .warn("Exception in event handler, continuing.", ex);
        }
      }
    } else if (connectionState == ConnectionState.OPERATIONAL) {
      for (int i = 0; i < l.length; i++) {
        try {
          l[i].operational(e);
        } catch (Exception ex) {
          Logger.getLogger(DynamicValuePropertyImpl.class)
              .warn("Exception in event handler, continuing.", ex);
        }
      }
    }
  }
 /* (non-Javadoc)
  * @see org.csstudio.dal.context.Linkable#removeLinkListener(org.csstudio.dal.context.LinkListener)
  */
 public void removeLinkListener(LinkListener<? extends Linkable> l) {
   linkListeners.remove(l);
 }
 /* (non-Javadoc)
  * @see org.csstudio.dal.AsynchronousContext#getResponseListeners()
  */
 public ResponseListener<?>[] getResponseListeners() {
   return (ResponseListener<?>[])
       responseListeners.toArray(new ResponseListener[responseListeners.size()]);
 }
 /* (non-Javadoc)
  * @see org.csstudio.dal.AsynchronousContext#removeResponseListener(org.csstudio.dal.ResponseListener)
  */
 public void removeResponseListener(ResponseListener<?> l) {
   responseListeners.remove(l);
 }
 /* (non-Javadoc)
  * @see org.csstudio.dal.AsynchronousContext#addResponseListener(org.csstudio.dal.ResponseListener)
  */
 public void addResponseListener(ResponseListener<?> l) {
   responseListeners.add(l);
 }