/**
   * Moves the operators from this process to another process, keeping all connections intact. TODO:
   * Test more rigorously. Do we register/unregister everything correctly?
   *
   * @return the number of ports the connections of which could not be restored
   */
  public int stealOperatorsFrom(ExecutionUnit otherUnit) {
    int failedReconnects = 0;

    // remember source and sink connections so we can reconnect them later.
    Map<String, InputPort> sourceMap = new HashMap<String, InputPort>();
    Map<String, OutputPort> sinkMap = new HashMap<String, OutputPort>();
    for (OutputPort source : otherUnit.getInnerSources().getAllPorts()) {
      if (source.isConnected()) {
        sourceMap.put(source.getName(), source.getDestination());
      }
    }
    otherUnit.getInnerSources().disconnectAll();
    for (InputPort sink : otherUnit.getInnerSinks().getAllPorts()) {
      if (sink.isConnected()) {
        sinkMap.put(sink.getName(), sink.getSource());
      }
    }
    otherUnit.getInnerSinks().disconnectAll();

    // Move operators
    Iterator<Operator> i = otherUnit.operators.iterator();
    while (i.hasNext()) {
      Operator operator = i.next();
      i.remove();
      otherUnit.unregister(operator);
      Process otherProcess = operator.getProcess();
      if (otherProcess != null) {
        operator.unregisterOperator(otherProcess);
      }
      this.operators.add(operator);
      operator.setEnclosingProcess(null);
      // operator.unregisterOperator(operator.getProcess());
      registerOperator(operator, true);
      // operator.registerOperator(this.getEnclosingOperator().getProcess());
    }

    // Rewire sources and sinks
    for (Map.Entry<String, InputPort> entry : sourceMap.entrySet()) {
      OutputPort mySource = getInnerSources().getPortByName(entry.getKey());
      if (mySource != null) {
        mySource.connectTo(entry.getValue());
      } else {
        failedReconnects++;
      }
    }
    getInnerSources().unlockPortExtenders();

    for (Map.Entry<String, OutputPort> entry : sinkMap.entrySet()) {
      InputPort mySink = getInnerSinks().getPortByName(entry.getKey());
      if (mySink != null) {
        entry.getValue().connectTo(mySink);
      } else {
        failedReconnects++;
      }
    }
    getInnerSinks().unlockPortExtenders();

    fireUpdate(this);
    return failedReconnects;
  }
 public void transformMetaData() {
   List<Operator> sorted = topologicalSort();
   for (Operator op : sorted) {
     op.transformMetaData();
   }
   if (sorted.size() != operators.size()) {
     List<Operator> remainder = new LinkedList<Operator>(operators);
     remainder.removeAll(sorted);
     for (Operator nodeInCircle : remainder) {
       for (OutputPort outputPort : nodeInCircle.getOutputPorts().getAllPorts()) {
         InputPort destination = outputPort.getDestination();
         if ((destination != null)
             && remainder.contains(destination.getPorts().getOwner().getOperator())) {
           if (destination.getSource() != null) {
             // (source can be null *during* a disconnect in which case
             // both the source and the destination fire an update
             // which leads to this inconsistent state)
             destination.addError(new OperatorLoopError(destination));
           }
           outputPort.addError(new OperatorLoopError(outputPort));
         }
       }
     }
   }
   getInnerSinks().checkPreconditions();
 }
 /**
  * Sorts the operators topologically, i.e. such that operator <var>i</var> in the returned
  * ordering has dependencies (i.e. connected {@link InputPort}s) only from operators
  * <var>0..i-1</var>.
  */
 public Vector<Operator> topologicalSort() {
   final Map<Operator, Integer> originalIndices = new HashMap<Operator, Integer>();
   for (int i = 0; i < operators.size(); i++) {
     originalIndices.put(operators.get(i), i);
   }
   EdgeCounter counter = new EdgeCounter(operators);
   for (Operator child : getOperators()) {
     for (OutputPort out : child.getOutputPorts().getAllPorts()) {
       InputPort dest = out.getDestination();
       if (dest != null) {
         counter.incNumEdges(dest.getPorts().getOwner().getOperator());
       }
     }
   }
   Vector<Operator> sorted = new Vector<Operator>();
   PriorityQueue<Operator> independentOperators =
       new PriorityQueue<Operator>(
           Math.max(1, operators.size()),
           new Comparator<Operator>() {
             @Override
             public int compare(Operator o1, Operator o2) {
               return originalIndices.get(o1) - originalIndices.get(o2);
             }
           });
   independentOperators.addAll(counter.getIndependentOperators());
   while (!independentOperators.isEmpty()) {
     Operator first = independentOperators.poll();
     sorted.add(first);
     for (OutputPort out : first.getOutputPorts().getAllPorts()) {
       InputPort dest = out.getDestination();
       if (dest != null) {
         Operator destOp = dest.getPorts().getOwner().getOperator();
         if (counter.decNumEdges(destOp) == 0) {
           // independentOperators.addFirst(destOp);
           independentOperators.add(destOp);
         }
       }
     }
   }
   return sorted;
 }
  private void cloneConnections(
      OutputPorts originalPorts,
      ExecutionUnit originalExecutionUnit,
      Map<String, Operator> clonedOperatorsByName) {
    for (OutputPort originalSource : originalPorts.getAllPorts()) {
      if (originalSource.isConnected()) {

        OutputPort mySource;
        if (originalPorts.getOwner().getOperator()
            == originalExecutionUnit.getEnclosingOperator()) {
          // this is an inner source
          mySource = getInnerSources().getPortByName(originalSource.getName());
          if (mySource == null) {
            throw new RuntimeException(
                "Error during clone: Corresponding source for "
                    + originalSource
                    + " not found (no such inner source).");
          }
        } else {
          // this is an output port
          Operator myOperator =
              clonedOperatorsByName.get(
                  originalSource.getPorts().getOwner().getOperator().getName());
          if (myOperator == null) {
            throw new RuntimeException(
                "Error during clone: Corresponding source for "
                    + originalSource
                    + " not found (no such operator).");
          }
          mySource = myOperator.getOutputPorts().getPortByName(originalSource.getName());
          if (mySource == null) {
            throw new RuntimeException(
                "Error during clone: Corresponding source for "
                    + originalSource
                    + " not found (no such output port).");
          }
        }

        InputPort originalDestination = originalSource.getDestination();
        InputPort myDestination;
        if (originalDestination.getPorts().getOwner().getOperator()
            == originalExecutionUnit.getEnclosingOperator()) {
          // this is an inner sink
          myDestination = getInnerSinks().getPortByName(originalDestination.getName());
          if (myDestination == null) {
            throw new RuntimeException(
                "Error during clone: Corresponding destination for "
                    + originalDestination
                    + " not found (no such inner sink).");
          }
        } else {
          // this is an input port
          Operator myOperator =
              clonedOperatorsByName.get(
                  originalDestination.getPorts().getOwner().getOperator().getName());
          if (myOperator == null) {
            throw new RuntimeException(
                "Error during clone: Corresponding destination for "
                    + originalDestination
                    + " not found (no such operator).");
          }
          myDestination = myOperator.getInputPorts().getPortByName(originalDestination.getName());
          if (myDestination == null) {
            throw new RuntimeException(
                "Error during clone: Corresponding destination for "
                    + originalDestination
                    + " not found (no such input port).");
          }
        }
        mySource.connectTo(myDestination);
      }
    }
  }