@Override
  public void undo() {
    propagateDatas(false);

    if (currentInputMetadata != null) {
      if (!currentInputMetadata.sameMetadataAs(oldInputMetadata, IMetadataColumn.OPTIONS_NONE)) {
        currentInputMetadata.setListColumns(oldInputMetadata.getListColumns());
        if (inputWasRepository) {
          inputNode.setPropertyValue(EParameterName.SCHEMA_TYPE.getName(), EmfComponent.REPOSITORY);
        }
      }
    }
    if (!currentOutputMetadata.sameMetadataAs(oldOutputMetadata, IMetadataColumn.OPTIONS_NONE)) {
      List<IMetadataColumn> currentColumns =
          new ArrayList<IMetadataColumn>(oldOutputMetadata.getListColumns());
      currentOutputMetadata.setListColumns(currentColumns);
      MetadataToolHelper.copyTable(oldOutputMetadata, currentOutputMetadata);
    }

    for (INodeConnector connector : node.getListConnector()) {
      if ((!connector.getName().equals(currentConnector))
          && connector.getBaseSchema().equals(currentConnector)) {
        MetadataToolHelper.copyTable(
            oldOutputMetadata, node.getMetadataFromConnector(connector.getName()));
      }
    }
    if (outputWasRepository) {
      node.setPropertyValue(EParameterName.SCHEMA_TYPE.getName(), EmfComponent.REPOSITORY);
    }
    for (ChangeMetadataCommand cmd : propagatedChange) {
      cmd.undo();
    }

    List<ColumnNameChanged> columnNameChanged =
        MetadataToolHelper.getColumnNameChanged(oldOutputMetadata, newOutputMetadata);
    ColumnListController.updateColumnList(node, columnNameChanged, true);
    // newOutputMetadata.setListColumns(new
    // ArrayList<IMetadataColumn>(oldOutputMetadata.getListColumns()));

    if (!internal) {
      updateColumnList(newOutputMetadata, oldOutputMetadata);
      ((Process) node.getProcess()).checkProcess();
    }
    refreshMetadataChanged();
  }
  private void propagateDatas(boolean isExecute) {
    String baseConnectorForCurrentNode =
        node.getConnectorFromName(currentConnector).getBaseSchema();

    // Propagate :
    if (outputdataContainer != null
        && (!outputdataContainer.getInputs().isEmpty()
            || !outputdataContainer.getOuputs().isEmpty())) {
      for (IODataComponent currentIO : outputdataContainer.getInputs()) {
        INode sourceNode = currentIO.getSource();
        if (currentIO.hasChanged()
            && (sourceNode
                .getConnectorFromName(currentIO.getConnection().getConnectorName())
                .getBaseSchema()
                .equals(baseConnectorForCurrentNode))) {
          sourceNode.metadataOutputChanged(currentIO, currentIO.getName());
          if (isExecute) {
            currentIO.setTable(oldInputMetadata);
            currentIO.setColumnNameChanged(null);
          } else {
            currentIO.setTable(newInputMetadata);
            currentIO.setColumnNameChanged(null);
          }
        }
      }
      for (IODataComponent currentIO : outputdataContainer.getOuputs()) {
        INodeConnector nodeConnector = null;
        String baseConnector = null;

        Node sourceNode = (Node) currentIO.getSource();
        nodeConnector =
            sourceNode.getConnectorFromName(currentIO.getConnection().getConnectorName());
        baseConnector = nodeConnector.getBaseSchema();

        INode targetNode = currentIO.getTarget();

        boolean sourceIsBuiltIn =
            ((Node) currentIO.getSource())
                .getConnectorFromType(currentIO.getConnection().getLineStyle())
                .isMultiSchema();

        boolean targetIsBuiltIn =
            ((Node) targetNode)
                .getConnectorFromType(currentIO.getConnection().getLineStyle())
                .isMultiSchema();
        boolean isJoblet = ((Node) targetNode).isJoblet();
        if (!isJoblet
            && baseConnector.equals(baseConnectorForCurrentNode)
            && (targetIsBuiltIn
                || (targetNode.getMetadataFromConnector(baseConnector) != null
                    && !targetNode
                        .getMetadataFromConnector(baseConnector)
                        .sameMetadataAs(newOutputMetadata)))) {

          targetNode.metadataInputChanged(currentIO, currentIO.getUniqueName());
          if (isExecute) {
            if (targetNode instanceof Node) {
              if (((Node) targetNode).getComponent().isSchemaAutoPropagated()
                  && getPropagate()
                  && targetNode.getMetadataList().size() > 0) {
                IMetadataTable tmpClone;
                if (sourceIsBuiltIn) {
                  IMetadataTable tab =
                      node.getMetadataTable(
                          currentIO.getConnection().getMetadataTable().getTableName());
                  if (tab == null && node.getJobletNode() != null) {
                    tab =
                        node.getJobletNode()
                            .getMetadataTable(
                                currentIO.getConnection().getMetadataTable().getTableName());
                  }
                  tmpClone = tab.clone(true);
                } else {
                  IMetadataTable tab =
                      node.getMetadataFromConnector(currentIO.getConnection().getConnectorName());
                  if (tab == null && node.getJobletNode() != null) {
                    tab =
                        node.getJobletNode()
                            .getMetadataFromConnector(currentIO.getConnection().getConnectorName());
                  }
                  tmpClone = tab.clone(true);
                }
                IMetadataTable toCopy = newOutputMetadata.clone();

                // wzhang modify to add feature 7611

                String dbmsId = null;
                IMetadataTable copy;
                if (((Node) targetNode).getMetadataFromConnector(baseConnector) != null) {
                  dbmsId = targetNode.getMetadataFromConnector(baseConnector).getDbms();
                  MetadataToolHelper.copyTable(dbmsId, toCopy, tmpClone);
                  toCopy = tmpClone;

                  // only if the target node have exactly the same connector
                  copy = ((Node) targetNode).getMetadataFromConnector(baseConnector).clone(true);
                } else {
                  final String mainConnector =
                      "FLOW"; // can only be FLOW right now for this case. //$NON-NLS-1$

                  dbmsId = targetNode.getMetadataFromConnector(mainConnector).getDbms();
                  MetadataToolHelper.copyTable(dbmsId, toCopy, tmpClone);
                  toCopy = tmpClone;
                  // if don't have the same connector, take the main connector of the component.

                  copy = ((Node) targetNode).getMetadataFromConnector(mainConnector).clone(true);
                }
                // MetadataTool.copyTable(toCopy, copy);
                // wzhang modify to add feature 7611
                MetadataToolHelper.copyTable(dbmsId, toCopy, copy);
                ChangeMetadataCommand cmd =
                    new ChangeMetadataCommand(targetNode, null, null, copy, inputSchemaParam);
                if (outputdataContainer.getOuputs().size() > 0) {
                  List<ColumnNameChanged> columnNameChanged =
                      outputdataContainer.getOuputs().get(0).getColumnNameChanged();
                  for (IODataComponent dataComp : cmd.outputdataContainer.getOuputs()) {
                    dataComp.setColumnNameChanged(columnNameChanged);
                  }
                }
                cmd.execute(true);
                propagatedChange.add(cmd);
              }
            }
            currentIO.setTable(oldOutputMetadata);
            currentIO.setColumnNameChanged(null);
          } else {
            if (targetNode instanceof Node) {
              if (!targetIsBuiltIn && getPropagate()) {
                if (((Node) targetNode).getComponent().isSchemaAutoPropagated()) {
                  if (outputdataContainer.getOuputs().size() > 0) {
                    List<ColumnNameChanged> columnNameChanged =
                        outputdataContainer.getOuputs().get(0).getColumnNameChanged();
                    for (ChangeMetadataCommand cmd : propagatedChange) {
                      for (IODataComponent dataComp : cmd.outputdataContainer.getOuputs()) {
                        dataComp.setColumnNameChanged(columnNameChanged);
                      }
                    }
                  }
                }
              }
            }

            currentIO.setTable(newOutputMetadata);
            currentIO.setColumnNameChanged(null);
          }
        }
      }
    } else if (dataComponent != null) {
      for (IConnection outgoingConnection : node.getOutgoingConnections()) {
        if (outgoingConnection.getConnectorName().equals(currentConnector)) {
          outgoingConnection
              .getTarget()
              .metadataInputChanged(dataComponent, outgoingConnection.getName());
        }
      }
    } else {
      if (!node.getOutgoingConnections().isEmpty()) {
        IMetadataTable relativeOldOutputMetadata = null;
        IMetadataTable relativeNewOutputMetadata = null;
        if (isExecute) {
          relativeOldOutputMetadata = oldOutputMetadata;
          relativeNewOutputMetadata = newOutputMetadata;
        } else {
          relativeOldOutputMetadata = newOutputMetadata;
          relativeNewOutputMetadata = oldOutputMetadata;
        }
        for (IConnection outgoingConnection : node.getOutgoingConnections()) {
          final Node target = (Node) outgoingConnection.getTarget();
          if (target != null && target.getExternalNode() != null) {
            List<IMetadataColumn> oldListColumns = relativeOldOutputMetadata.getListColumns();
            List<IMetadataColumn> newListColumns = relativeNewOutputMetadata.getListColumns();
            List<ColumnNameChanged> columnNameChanges = new ArrayList<ColumnNameChanged>();
            int size = oldListColumns.size();
            int newSize = newListColumns.size();
            if (newSize < size) {
              size = newSize;
            }
            IODataComponent output =
                new IODataComponent(outgoingConnection, relativeNewOutputMetadata);
            if (newListColumns != null) {
              List<ColumnNameChanged> newColumnsList = output.getNewMetadataColumns();
              // new added columns list
              Set<String> newAddedColumns = new HashSet<String>();
              // newest columns after user changed
              Set<String> newestColumns = new HashSet<String>();

              // init
              if (newColumnsList != null) {
                for (ColumnNameChanged columnChanged : newColumnsList) {
                  newAddedColumns.add(columnChanged.getNewName());
                }
              }
              for (IMetadataColumn metadataColumn : newListColumns) {
                newestColumns.add(metadataColumn.getLabel());
              }

              // check
              for (int i = 0; i < size; i++) {
                IMetadataColumn oldMetadataColumn = oldListColumns.get(i);
                String columnName = oldMetadataColumn.getLabel();
                // if this column(before changing) is not exists in the new columns(after changing),
                // there are two possible truth: 1. this column has been renamed; 2. this column has
                // been removed
                if (!newestColumns.contains(columnName)) {
                  IMetadataColumn newMetadataColumn = newListColumns.get(i);
                  String newColumnNameAtThisIndex = newMetadataColumn.getLabel();
                  // if the column at the same position in new table is a new column(two possible
                  // truth: 1. an old column's name has been changed; 2. user add a new column);
                  // For now, Seems it is very hard to judge whether it is a renamed column or a new
                  // column, so we suppose the more possible truth is that it is a renamed column
                  if (newAddedColumns.contains(newColumnNameAtThisIndex)) {
                    columnNameChanges.add(
                        new ColumnNameChanged(columnName, newColumnNameAtThisIndex));
                  }
                }
              }
            }

            if (GlobalServiceRegister.getDefault().isServiceRegistered(IXmlMapService.class)) {
              final IXmlMapService service =
                  (IXmlMapService)
                      GlobalServiceRegister.getDefault().getService(IXmlMapService.class);
              if (service.isXmlMapComponent(target.getExternalNode())) {
                output.setColumnNameChanged(columnNameChanges);
                target.metadataInputChanged(output, outgoingConnection.getName());
              }
            }
            if (GlobalServiceRegister.getDefault().isServiceRegistered(ISparkMapService.class)) {
              final ISparkMapService service =
                  (ISparkMapService)
                      GlobalServiceRegister.getDefault().getService(ISparkMapService.class);
              if (service.isSparkMapComponent(target.getExternalNode())) {
                output.setColumnNameChanged(columnNameChanges);
                target.metadataInputChanged(output, outgoingConnection.getName());
              }
            }

            if (GlobalServiceRegister.getDefault().isServiceRegistered(IDbMapService.class)) {
              final IDbMapService service =
                  (IDbMapService)
                      GlobalServiceRegister.getDefault().getService(IDbMapService.class);
              if (service.isDbMapComponent(target.getExternalNode())) {
                // TDI-25307:should setColumNameChanged here for ELtDbMap in case the propagate
                // schema
                // does not affect it.
                output.setColumnNameChanged(columnNameChanges);
                target.metadataInputChanged(output, outgoingConnection.getName());
              }
            }
          }
        }
      }
    }

    if (inputdataContainer != null) {
      for (IODataComponent currentIO : inputdataContainer.getOuputs()) {
        if (currentIO.hasChanged()
            && (currentIO
                .getSource()
                .getConnectorFromName(currentIO.getConnection().getConnectorName())
                .getBaseSchema()
                .equals(currentConnector))) {
          INode targetNode = currentIO.getTarget();
          targetNode.metadataInputChanged(currentIO, currentIO.getUniqueName());
          if (isExecute) {
            currentIO.setTable(oldInputMetadata);
            currentIO.setColumnNameChanged(null);
          } else {
            currentIO.setTable(newInputMetadata);
            currentIO.setColumnNameChanged(null);
          }
        }
      }
    }
    // End propagate
  }