/**
   * Deeply list the opaque ports connected to this port on the outside. Begin by listing the ports
   * that are connected to this port. If any of those are transparent ports that we are connected to
   * from the inside, then list all the ports deeply connected on the outside to that transparent
   * port. If any are transparent ports that we are connected to from the outside, then list opaque
   * ports deeply inside that port. Note that a port may be listed more than once. The path argument
   * is the path from the port that originally calls this method to this port. If this port is
   * already on the list of ports on the path to this port in deeply traversing the topology, then
   * there is a loop in the topology, and an InvalidStateException is thrown. This method not
   * synchronized on the workspace, so the caller should.
   *
   * @param path The list of ports on the path to this port in deeply traversing the topology.
   * @return An unmodifiable list of ComponentPort objects.
   */
  protected List _deepConnectedPortList(LinkedList path) {
    if (_deepLinkedPortsVersion == _workspace.getVersion()) {
      // Cache is valid.  Use it.
      return _deepLinkedPorts;
    }

    if (path == null) {
      path = new LinkedList();
    } else {
      if (path.indexOf(this) >= 0) {
        throw new InvalidStateException(path, "Loop in topology!");
      }
    }

    path.add(0, this);

    Iterator nearRelations = linkedRelationList().iterator();
    LinkedList result = new LinkedList();

    while (nearRelations.hasNext()) {
      ComponentRelation relation = (ComponentRelation) nearRelations.next();

      // A null link (supported since indexed links) might
      // yield a null relation here. EAL 7/19/00.
      if (relation != null) {
        Iterator connectedPorts = relation.linkedPortList(this).iterator();

        while (connectedPorts.hasNext()) {
          ComponentPort port = (ComponentPort) connectedPorts.next();

          // NOTE: If level-crossing transitions are not allowed,
          // then a simpler test than that of the following
          // would work.
          if (port._isInsideLinkable(relation.getContainer())) {
            // We are coming at the port from the inside.
            if (port.isOpaque()) {
              result.add(port);
            } else {
              // Port is transparent
              result.addAll(port._deepConnectedPortList(path));
            }
          } else {
            // We are coming at the port from the outside.
            if (port.isOpaque()) {
              result.add(port);
            } else {
              // It is transparent.
              result.addAll(port._deepInsidePortList(path));
            }
          }
        }
      }
    }

    _deepLinkedPorts = Collections.unmodifiableList(result);
    _deepLinkedPortsVersion = _workspace.getVersion();
    path.remove(0);
    return _deepLinkedPorts;
  }