@SuppressWarnings("deprecation")
 private void compatibleSaveRep(
     StepMetaInterface stepMetaInterface,
     KettleDatabaseRepository repository,
     ObjectId id_transformation,
     ObjectId objectId)
     throws KettleException {
   stepMetaInterface.saveRep(repository, id_transformation, objectId);
 }
 /**
  * Compatible loading of metadata for v4 style plugins using deprecated methods.
  *
  * @param stepMetaInterface
  * @param repository
  * @param objectId
  * @param databases
  * @throws KettleException
  */
 @SuppressWarnings("deprecation")
 private void readRepCompatibleStepMeta(
     StepMetaInterface stepMetaInterface,
     KettleDatabaseRepository repository,
     ObjectId objectId,
     List<DatabaseMeta> databases)
     throws KettleException {
   stepMetaInterface.readRep(repository, objectId, databases, null);
 }
  /**
   * Reads in the fields from the previous steps and from the ONE next step and opens an
   * EnterMappingDialog with this information. After the user did the mapping, those information is
   * put into the Select/Rename table.
   */
  private void generateMappings() {

    // Determine the source and target fields...
    //
    RowMetaInterface sourceFields;
    RowMetaInterface targetFields;

    try {
      sourceFields = transMeta.getPrevStepFields(stepMeta);
    } catch (KettleException e) {
      new ErrorDialog(
          shell,
          BaseMessages.getString(
              PKG, "IngresVectorWiseLoaderDialog.DoMapping.UnableToFindSourceFields.Title"),
          BaseMessages.getString(
              PKG, "IngresVectorWiseLoaderDialog.DoMapping.UnableToFindSourceFields.Message"),
          e);
      return;
    }

    // refresh data
    input.setDatabaseMeta(transMeta.findDatabase(serverConnection.getText()));
    input.setTablename(transMeta.environmentSubstitute(wTable.getText()));
    StepMetaInterface stepMetaInterface = stepMeta.getStepMetaInterface();
    try {
      targetFields = stepMetaInterface.getRequiredFields(transMeta);
    } catch (KettleException e) {
      new ErrorDialog(
          shell,
          BaseMessages.getString(
              PKG, "IngresVectorWiseLoaderDialog.DoMapping.UnableToFindTargetFields.Title"),
          BaseMessages.getString(
              PKG, "IngresVectorWiseLoaderDialog.DoMapping.UnableToFindTargetFields.Message"),
          e);
      return;
    }

    String[] inputNames = new String[sourceFields.size()];
    for (int i = 0; i < sourceFields.size(); i++) {
      ValueMetaInterface value = sourceFields.getValueMeta(i);
      inputNames[i] =
          value.getName() + EnterMappingDialog.STRING_ORIGIN_SEPARATOR + value.getOrigin() + ")";
    }

    // Create the existing mapping list...
    //
    List<SourceToTargetMapping> mappings = new ArrayList<SourceToTargetMapping>();
    StringBuffer missingSourceFields = new StringBuffer();
    StringBuffer missingTargetFields = new StringBuffer();

    int nrFields = wFields.nrNonEmpty();
    for (int i = 0; i < nrFields; i++) {
      TableItem item = wFields.getNonEmpty(i);
      String source = item.getText(2);
      String target = item.getText(1);

      int sourceIndex = sourceFields.indexOfValue(source);
      if (sourceIndex < 0) {
        missingSourceFields.append(Const.CR + "   " + source + " --> " + target);
      }
      int targetIndex = targetFields.indexOfValue(target);
      if (targetIndex < 0) {
        missingTargetFields.append(Const.CR + "   " + source + " --> " + target);
      }
      if (sourceIndex < 0 || targetIndex < 0) {
        continue;
      }

      SourceToTargetMapping mapping = new SourceToTargetMapping(sourceIndex, targetIndex);
      mappings.add(mapping);
    }

    // show a confirm dialog if some missing field was found
    //
    if (missingSourceFields.length() > 0 || missingTargetFields.length() > 0) {

      String message = "";
      if (missingSourceFields.length() > 0) {
        message +=
            BaseMessages.getString(
                    PKG,
                    "IngresVectorWiseLoaderDialog.DoMapping.SomeSourceFieldsNotFound",
                    missingSourceFields.toString())
                + Const.CR;
      }
      if (missingTargetFields.length() > 0) {
        message +=
            BaseMessages.getString(
                    PKG,
                    "IngresVectorWiseLoaderDialog.DoMapping.SomeTargetFieldsNotFound",
                    missingSourceFields.toString())
                + Const.CR;
      }
      message += Const.CR;
      message +=
          BaseMessages.getString(
                  PKG, "IngresVectorWiseLoaderDialog.DoMapping.SomeFieldsNotFoundContinue")
              + Const.CR;
      MessageDialog.setDefaultImage(GUIResource.getInstance().getImageSpoon());
      boolean goOn =
          MessageDialog.openConfirm(
              shell,
              BaseMessages.getString(
                  PKG, "IngresVectorWiseLoaderDialog.DoMapping.SomeFieldsNotFoundTitle"),
              message);
      if (!goOn) {
        return;
      }
    }
    EnterMappingDialog d =
        new EnterMappingDialog(
            IngresVectorwiseLoaderDialog.this.shell,
            sourceFields.getFieldNames(),
            targetFields.getFieldNames(),
            mappings);
    mappings = d.open();

    // mappings == null if the user pressed cancel
    //
    if (mappings != null) {
      // Clear and re-populate!
      //
      wFields.table.removeAll();
      wFields.table.setItemCount(mappings.size());
      for (int i = 0; i < mappings.size(); i++) {
        SourceToTargetMapping mapping = mappings.get(i);
        TableItem item = wFields.table.getItem(i);
        item.setText(2, sourceFields.getValueMeta(mapping.getSourcePosition()).getName());
        item.setText(1, targetFields.getValueMeta(mapping.getTargetPosition()).getName());
      }
      wFields.setRowNums();
      wFields.optWidth(true);
    }
  }
  public DataNode elementToDataNode(final RepositoryElementInterface element)
      throws KettleException {
    TransMeta transMeta = (TransMeta) element;

    DataNode rootNode = new DataNode(NODE_TRANS);

    DataNode stepsNode = rootNode.addNode(NODE_STEPS);

    if (transMeta.getPrivateTransformationDatabases() != null) {
      // save all private transformations database name http://jira.pentaho.com/browse/PPP-3405
      DataNode privateDatabaseNode = rootNode.addNode(NODE_TRANS_PRIVATE_DATABASES);
      for (String privateDatabase : transMeta.getPrivateTransformationDatabases()) {
        privateDatabaseNode.addNode(privateDatabase);
      }
    }
    // Also save all the steps in the transformation!
    //
    int stepNr = 0;
    for (StepMeta step : transMeta.getSteps()) {
      stepNr++;
      DataNode stepNode =
          stepsNode.addNode(
              sanitizeNodeName(step.getName()) + "_" + stepNr + EXT_STEP); // $NON-NLS-1$

      // Store the main data
      //
      stepNode.setProperty(PROP_NAME, step.getName());
      stepNode.setProperty(PROP_DESCRIPTION, step.getDescription());
      stepNode.setProperty(PROP_STEP_TYPE, step.getStepID());
      stepNode.setProperty(PROP_STEP_DISTRIBUTE, step.isDistributes());
      stepNode.setProperty(
          PROP_STEP_ROW_DISTRIBUTION,
          step.getRowDistribution() == null ? null : step.getRowDistribution().getCode());
      stepNode.setProperty(PROP_STEP_COPIES, step.getCopies());
      stepNode.setProperty(PROP_STEP_COPIES_STRING, step.getCopiesString());
      stepNode.setProperty(PROP_STEP_GUI_LOCATION_X, step.getLocation().x);
      stepNode.setProperty(PROP_STEP_GUI_LOCATION_Y, step.getLocation().y);
      stepNode.setProperty(PROP_STEP_GUI_DRAW, step.isDrawn());

      // Also save the step group attributes map
      //
      AttributesMapUtil.saveAttributesMap(stepNode, step);

      // Save the step metadata using the repository save method, NOT XML
      // That is because we want to keep the links to databases, conditions, etc by ID, not name.
      //
      StepMetaInterface stepMetaInterface = step.getStepMetaInterface();
      DataNode stepCustomNode = new DataNode(NODE_STEP_CUSTOM);
      Repository proxy = new RepositoryProxy(stepCustomNode);
      compatibleSaveRep(stepMetaInterface, proxy, null, null);
      stepMetaInterface.saveRep(proxy, proxy.getMetaStore(), null, null);
      stepNode.addNode(stepCustomNode);

      // Save the partitioning information by reference as well...
      //
      StepPartitioningMeta partitioningMeta = step.getStepPartitioningMeta();
      if (partitioningMeta != null
          && partitioningMeta.getPartitionSchema() != null
          && partitioningMeta.isPartitioned()) {
        DataNodeRef ref =
            new DataNodeRef(partitioningMeta.getPartitionSchema().getObjectId().getId());
        stepNode.setProperty(PROP_PARTITIONING_SCHEMA, ref);
        stepNode.setProperty(
            PROP_PARTITIONING_METHOD, partitioningMeta.getMethodCode()); // method of partitioning
        if (partitioningMeta.getPartitioner() != null) {
          DataNode partitionerCustomNode = new DataNode(NODE_PARTITIONER_CUSTOM);
          proxy = new RepositoryProxy(partitionerCustomNode);
          partitioningMeta.getPartitioner().saveRep(proxy, null, null);
          stepNode.addNode(partitionerCustomNode);
        }
      }

      // Save the clustering information as well...
      //
      stepNode.setProperty(
          PROP_CLUSTER_SCHEMA,
          step.getClusterSchema() == null
              ? ""
              : step.getClusterSchema() //$NON-NLS-1$
                  .getName());

      // Save the error hop metadata
      //
      StepErrorMeta stepErrorMeta = step.getStepErrorMeta();
      if (stepErrorMeta != null) {
        stepNode.setProperty(
            PROP_STEP_ERROR_HANDLING_SOURCE_STEP,
            stepErrorMeta.getSourceStep() != null
                ? stepErrorMeta.getSourceStep().getName()
                : ""); //$NON-NLS-1$
        stepNode.setProperty(
            PROP_STEP_ERROR_HANDLING_TARGET_STEP,
            stepErrorMeta.getTargetStep() != null
                ? stepErrorMeta.getTargetStep().getName()
                : ""); //$NON-NLS-1$
        stepNode.setProperty(PROP_STEP_ERROR_HANDLING_IS_ENABLED, stepErrorMeta.isEnabled());
        stepNode.setProperty(
            PROP_STEP_ERROR_HANDLING_NR_VALUENAME, stepErrorMeta.getNrErrorsValuename());
        stepNode.setProperty(
            PROP_STEP_ERROR_HANDLING_DESCRIPTIONS_VALUENAME,
            stepErrorMeta.getErrorDescriptionsValuename());
        stepNode.setProperty(
            PROP_STEP_ERROR_HANDLING_FIELDS_VALUENAME, stepErrorMeta.getErrorFieldsValuename());
        stepNode.setProperty(
            PROP_STEP_ERROR_HANDLING_CODES_VALUENAME, stepErrorMeta.getErrorCodesValuename());
        stepNode.setProperty(PROP_STEP_ERROR_HANDLING_MAX_ERRORS, stepErrorMeta.getMaxErrors());
        stepNode.setProperty(
            PROP_STEP_ERROR_HANDLING_MAX_PCT_ERRORS, stepErrorMeta.getMaxPercentErrors());
        stepNode.setProperty(
            PROP_STEP_ERROR_HANDLING_MIN_PCT_ROWS, stepErrorMeta.getMinPercentRows());
      }
    }

    // Save the notes
    //
    DataNode notesNode = rootNode.addNode(NODE_NOTES);
    notesNode.setProperty(PROP_NR_NOTES, transMeta.nrNotes());
    for (int i = 0; i < transMeta.nrNotes(); i++) {
      NotePadMeta note = transMeta.getNote(i);
      DataNode noteNode = notesNode.addNode(NOTE_PREFIX + i);

      noteNode.setProperty(PROP_XML, note.getXML());
    }

    // Finally, save the hops
    //
    DataNode hopsNode = rootNode.addNode(NODE_HOPS);
    hopsNode.setProperty(PROP_NR_HOPS, transMeta.nrTransHops());
    for (int i = 0; i < transMeta.nrTransHops(); i++) {
      TransHopMeta hop = transMeta.getTransHop(i);
      DataNode hopNode = hopsNode.addNode(TRANS_HOP_PREFIX + i);
      hopNode.setProperty(TRANS_HOP_FROM, hop.getFromStep().getName());
      hopNode.setProperty(TRANS_HOP_TO, hop.getToStep().getName());
      hopNode.setProperty(TRANS_HOP_ENABLED, hop.isEnabled());
    }

    // Parameters
    //
    String[] paramKeys = transMeta.listParameters();
    DataNode paramsNode = rootNode.addNode(NODE_PARAMETERS);
    paramsNode.setProperty(PROP_NR_PARAMETERS, paramKeys == null ? 0 : paramKeys.length);

    for (int idx = 0; idx < paramKeys.length; idx++) {
      DataNode paramNode = paramsNode.addNode(TRANS_PARAM_PREFIX + idx);
      String key = paramKeys[idx];
      String description = transMeta.getParameterDescription(paramKeys[idx]);
      String defaultValue = transMeta.getParameterDefault(paramKeys[idx]);

      paramNode.setProperty(PARAM_KEY, key != null ? key : ""); // $NON-NLS-1$
      paramNode.setProperty(PARAM_DEFAULT, defaultValue != null ? defaultValue : ""); // $NON-NLS-1$
      paramNode.setProperty(PARAM_DESC, description != null ? description : ""); // $NON-NLS-1$
    }

    // Let's not forget to save the details of the transformation itself.
    // This includes logging information, parameters, etc.
    //
    saveTransformationDetails(rootNode, transMeta);

    return rootNode;
  }
  public void dataNodeToElement(final DataNode rootNode, final RepositoryElementInterface element)
      throws KettleException {
    TransMeta transMeta = (TransMeta) element;

    List<String> privateTransformationDatabases = null;
    // read the private databases
    DataNode privateDatabases = rootNode.getNode(NODE_TRANS_PRIVATE_DATABASES);
    // if we have node than we use new format we could remove unexpected node
    if (privateDatabases != null) {
      privateTransformationDatabases = new ArrayList<String>();
      for (DataNode privateDatabase : privateDatabases.getNodes()) {
        privateTransformationDatabases.add(privateDatabase.getName());
      }
    }
    transMeta.setPrivateTransformationDatabases(privateTransformationDatabases);

    // read the steps...
    //
    DataNode stepsNode = rootNode.getNode(NODE_STEPS);
    for (DataNode stepNode : stepsNode.getNodes()) {

      StepMeta stepMeta = new StepMeta(new StringObjectId(stepNode.getId().toString()));
      stepMeta.setParentTransMeta(transMeta); // for tracing, retain hierarchy

      // Read the basics
      //
      stepMeta.setName(getString(stepNode, PROP_NAME));
      if (stepNode.hasProperty(PROP_DESCRIPTION)) {
        stepMeta.setDescription(getString(stepNode, PROP_DESCRIPTION));
      }
      stepMeta.setDistributes(stepNode.getProperty(PROP_STEP_DISTRIBUTE).getBoolean());
      DataProperty rowDistributionProperty = stepNode.getProperty(PROP_STEP_ROW_DISTRIBUTION);
      String rowDistributionCode =
          rowDistributionProperty == null ? null : rowDistributionProperty.getString();
      RowDistributionInterface rowDistribution =
          PluginRegistry.getInstance()
              .loadClass(
                  RowDistributionPluginType.class,
                  rowDistributionCode,
                  RowDistributionInterface.class);
      stepMeta.setRowDistribution(rowDistribution);
      stepMeta.setDraw(stepNode.getProperty(PROP_STEP_GUI_DRAW).getBoolean());
      int copies = (int) stepNode.getProperty(PROP_STEP_COPIES).getLong();
      String copiesString =
          stepNode.getProperty(PROP_STEP_COPIES_STRING) != null
              ? stepNode.getProperty(PROP_STEP_COPIES_STRING).getString()
              : StringUtils.EMPTY;
      if (!Const.isEmpty(copiesString)) {
        stepMeta.setCopiesString(copiesString);
      } else {
        stepMeta.setCopies(copies); // for backward compatibility
      }

      int x = (int) stepNode.getProperty(PROP_STEP_GUI_LOCATION_X).getLong();
      int y = (int) stepNode.getProperty(PROP_STEP_GUI_LOCATION_Y).getLong();
      stepMeta.setLocation(x, y);

      // Load the group attributes map
      //
      AttributesMapUtil.loadAttributesMap(stepNode, stepMeta);

      String stepType = getString(stepNode, PROP_STEP_TYPE);

      // Create a new StepMetaInterface object...
      //
      PluginRegistry registry = PluginRegistry.getInstance();
      PluginInterface stepPlugin = registry.findPluginWithId(StepPluginType.class, stepType);

      StepMetaInterface stepMetaInterface = null;
      if (stepPlugin != null) {
        stepMetaInterface = (StepMetaInterface) registry.loadClass(stepPlugin);
        stepType =
            stepPlugin.getIds()[0]; // revert to the default in case we loaded an alternate version
      } else {
        stepMeta.setStepMetaInterface(
            (StepMetaInterface) new MissingTrans(stepMeta.getName(), stepType));
        transMeta.addMissingTrans((MissingTrans) stepMeta.getStepMetaInterface());
      }

      stepMeta.setStepID(stepType);

      // Read the metadata from the repository too...
      //
      RepositoryProxy proxy = new RepositoryProxy(stepNode.getNode(NODE_STEP_CUSTOM));
      if (!stepMeta.isMissing()) {
        readRepCompatibleStepMeta(stepMetaInterface, proxy, null, transMeta.getDatabases());
        stepMetaInterface.readRep(proxy, transMeta.getMetaStore(), null, transMeta.getDatabases());
        stepMeta.setStepMetaInterface(stepMetaInterface);
      }

      // Get the partitioning as well...
      StepPartitioningMeta stepPartitioningMeta = new StepPartitioningMeta();
      if (stepNode.hasProperty(PROP_PARTITIONING_SCHEMA)) {
        String partSchemaId =
            stepNode.getProperty(PROP_PARTITIONING_SCHEMA).getRef().getId().toString();
        String schemaName =
            repo.loadPartitionSchema(new StringObjectId(partSchemaId), null).getName();

        stepPartitioningMeta.setPartitionSchemaName(schemaName);
        String methodCode = getString(stepNode, PROP_PARTITIONING_METHOD);
        stepPartitioningMeta.setMethod(StepPartitioningMeta.getMethod(methodCode));
        if (stepPartitioningMeta.getPartitioner() != null) {
          proxy = new RepositoryProxy(stepNode.getNode(NODE_PARTITIONER_CUSTOM));
          stepPartitioningMeta.getPartitioner().loadRep(proxy, null);
        }
        stepPartitioningMeta.hasChanged(true);
      }
      stepMeta.setStepPartitioningMeta(stepPartitioningMeta);

      stepMeta
          .getStepPartitioningMeta()
          .setPartitionSchemaAfterLoading(transMeta.getPartitionSchemas());
      // Get the cluster schema name
      String clusterSchemaName = getString(stepNode, PROP_CLUSTER_SCHEMA);
      stepMeta.setClusterSchemaName(clusterSchemaName);
      if (clusterSchemaName != null && transMeta.getClusterSchemas() != null) {
        // Get the cluster schema from the given name
        for (ClusterSchema clusterSchema : transMeta.getClusterSchemas()) {
          if (clusterSchema.getName().equals(clusterSchemaName)) {
            stepMeta.setClusterSchema(clusterSchema);
            break;
          }
        }
      }

      transMeta.addStep(stepMeta);
    }

    for (DataNode stepNode : stepsNode.getNodes()) {

      ObjectId stepObjectId = new StringObjectId(stepNode.getId().toString());
      StepMeta stepMeta = StepMeta.findStep(transMeta.getSteps(), stepObjectId);

      // Also load the step error handling metadata
      //
      if (stepNode.hasProperty(PROP_STEP_ERROR_HANDLING_SOURCE_STEP)) {
        StepErrorMeta meta = new StepErrorMeta(transMeta, stepMeta);
        meta.setTargetStep(
            StepMeta.findStep(
                transMeta.getSteps(),
                stepNode.getProperty(PROP_STEP_ERROR_HANDLING_TARGET_STEP).getString()));
        meta.setEnabled(stepNode.getProperty(PROP_STEP_ERROR_HANDLING_IS_ENABLED).getBoolean());
        meta.setNrErrorsValuename(getString(stepNode, PROP_STEP_ERROR_HANDLING_NR_VALUENAME));
        meta.setErrorDescriptionsValuename(
            getString(stepNode, PROP_STEP_ERROR_HANDLING_DESCRIPTIONS_VALUENAME));
        meta.setErrorFieldsValuename(
            getString(stepNode, PROP_STEP_ERROR_HANDLING_FIELDS_VALUENAME));
        meta.setErrorCodesValuename(getString(stepNode, PROP_STEP_ERROR_HANDLING_CODES_VALUENAME));
        meta.setMaxErrors(getString(stepNode, PROP_STEP_ERROR_HANDLING_MAX_ERRORS));
        meta.setMaxPercentErrors(getString(stepNode, PROP_STEP_ERROR_HANDLING_MAX_PCT_ERRORS));
        meta.setMinPercentRows(getString(stepNode, PROP_STEP_ERROR_HANDLING_MIN_PCT_ROWS));
        meta.getSourceStep().setStepErrorMeta(meta); // a bit of a trick, I know.
      }
    }

    // Have all StreamValueLookups, etc. reference the correct source steps...
    //
    for (int i = 0; i < transMeta.nrSteps(); i++) {
      StepMeta stepMeta = transMeta.getStep(i);
      StepMetaInterface sii = stepMeta.getStepMetaInterface();
      if (sii != null) {
        sii.searchInfoAndTargetSteps(transMeta.getSteps());
      }
    }

    // Read the notes...
    //
    DataNode notesNode = rootNode.getNode(NODE_NOTES);
    int nrNotes = (int) notesNode.getProperty(PROP_NR_NOTES).getLong();
    for (DataNode noteNode : notesNode.getNodes()) {
      String xml = getString(noteNode, PROP_XML);
      transMeta.addNote(
          new NotePadMeta(
              XMLHandler.getSubNode(XMLHandler.loadXMLString(xml), NotePadMeta.XML_TAG)));
    }
    if (transMeta.nrNotes() != nrNotes) {
      throw new KettleException(
          "The number of notes read ["
              + transMeta.nrNotes()
              + "] was not the number we expected ["
              + nrNotes
              + "]");
    }

    // Read the hops...
    //
    DataNode hopsNode = rootNode.getNode(NODE_HOPS);
    int nrHops = (int) hopsNode.getProperty(PROP_NR_HOPS).getLong();
    for (DataNode hopNode : hopsNode.getNodes()) {
      String stepFromName = getString(hopNode, TRANS_HOP_FROM);
      String stepToName = getString(hopNode, TRANS_HOP_TO);
      boolean enabled = true;
      if (hopNode.hasProperty(TRANS_HOP_ENABLED)) {
        enabled = hopNode.getProperty(TRANS_HOP_ENABLED).getBoolean();
      }

      StepMeta stepFrom = StepMeta.findStep(transMeta.getSteps(), stepFromName);
      StepMeta stepTo = StepMeta.findStep(transMeta.getSteps(), stepToName);

      // Make sure to only accept valid hops PDI-5519
      //
      if (stepFrom != null && stepTo != null) {
        transMeta.addTransHop(new TransHopMeta(stepFrom, stepTo, enabled));
      }
    }
    if (transMeta.nrTransHops() != nrHops) {
      throw new KettleException(
          "The number of hops read ["
              + transMeta.nrTransHops()
              + "] was not the number we expected ["
              + nrHops
              + "]");
    }

    // Load the details at the end, to make sure we reference the databases correctly, etc.
    //
    loadTransformationDetails(rootNode, transMeta);

    transMeta.eraseParameters();

    DataNode paramsNode = rootNode.getNode(NODE_PARAMETERS);

    int count = (int) paramsNode.getProperty(PROP_NR_PARAMETERS).getLong();
    for (int idx = 0; idx < count; idx++) {
      DataNode paramNode = paramsNode.getNode(TRANS_PARAM_PREFIX + idx);
      String key = getString(paramNode, PARAM_KEY);
      String def = getString(paramNode, PARAM_DEFAULT);
      String desc = getString(paramNode, PARAM_DESC);
      transMeta.addParameterDefinition(key, def, desc);
    }

    transMeta.activateParameters();
  }
  @Override
  public AbstractMeta decode(String graphXml) throws Exception {
    mxGraph graph = new mxGraph();
    mxCodec codec = new mxCodec();
    Document doc = mxUtils.parseXml(graphXml);
    codec.decode(doc.getDocumentElement(), graph.getModel());
    mxCell root = (mxCell) graph.getDefaultParent();

    TransMeta transMeta = new TransMeta();
    decodeCommRootAttr(root, transMeta);
    transMeta.setTransstatus(Const.toInt(root.getAttribute("trans_status"), -1));
    transMeta.setTransversion(root.getAttribute("trans_version"));

    if (transMeta.getRepository() != null)
      transMeta.setSharedObjects(transMeta.getRepository().readTransSharedObjects(transMeta));
    else transMeta.setSharedObjects(transMeta.readSharedObjects());

    transMeta.importFromMetaStore();

    decodeDatabases(root, transMeta);
    decodeNote(graph, transMeta);

    int count = graph.getModel().getChildCount(root);
    for (int i = 0; i < count; i++) {
      mxCell cell = (mxCell) graph.getModel().getChildAt(root, i);
      if (cell.isVertex()) {
        Element e = (Element) cell.getValue();
        if (PropsUI.TRANS_STEP_NAME.equals(e.getTagName())) {
          StepDecoder stepDecoder = (StepDecoder) PluginFactory.getBean(cell.getAttribute("ctype"));
          StepMeta stepMeta =
              stepDecoder.decodeStep(cell, transMeta.getDatabases(), transMeta.getMetaStore());
          stepMeta.setParentTransMeta(transMeta);
          if (stepMeta.isMissing()) {
            transMeta.addMissingTrans((MissingTrans) stepMeta.getStepMetaInterface());
          }

          StepMeta check = transMeta.findStep(stepMeta.getName());
          if (check != null) {
            if (!check.isShared()) {
              // Don't overwrite shared objects
              transMeta.addOrReplaceStep(stepMeta);
            } else {
              check.setDraw(stepMeta.isDrawn()); // Just keep the  drawn flag  and location
              check.setLocation(stepMeta.getLocation());
            }
          } else {
            transMeta.addStep(stepMeta); // simply add it.
          }
        }
      }
    }

    // Have all StreamValueLookups, etc. reference the correct source steps...
    //
    for (int i = 0; i < transMeta.nrSteps(); i++) {
      StepMeta stepMeta = transMeta.getStep(i);
      StepMetaInterface sii = stepMeta.getStepMetaInterface();
      if (sii != null) {
        sii.searchInfoAndTargetSteps(transMeta.getSteps());
      }
    }

    count = graph.getModel().getChildCount(root);
    for (int i = 0; i < count; i++) {
      mxCell cell = (mxCell) graph.getModel().getChildAt(root, i);
      if (cell.isEdge()) {
        mxCell source = (mxCell) cell.getSource();
        mxCell target = (mxCell) cell.getTarget();

        TransHopMeta hopinf = new TransHopMeta(null, null, true);
        String[] stepNames = transMeta.getStepNames();
        for (int j = 0; j < stepNames.length; j++) {
          if (stepNames[j].equalsIgnoreCase(source.getAttribute("label")))
            hopinf.setFromStep(transMeta.getStep(j));
          if (stepNames[j].equalsIgnoreCase(target.getAttribute("label")))
            hopinf.setToStep(transMeta.getStep(j));
        }
        transMeta.addTransHop(hopinf);
      }
    }

    JSONObject jsonObject = JSONObject.fromObject(root.getAttribute("transLogTable"));
    TransLogTable transLogTable = transMeta.getTransLogTable();
    transLogTable.setConnectionName(jsonObject.optString("connection"));
    transLogTable.setSchemaName(jsonObject.optString("schema"));
    transLogTable.setTableName(jsonObject.optString("table"));
    transLogTable.setLogSizeLimit(jsonObject.optString("size_limit_lines"));
    transLogTable.setLogInterval(jsonObject.optString("interval"));
    transLogTable.setTimeoutInDays(jsonObject.optString("timeout_days"));
    JSONArray jsonArray = jsonObject.optJSONArray("fields");
    if (jsonArray != null) {
      for (int i = 0; i < jsonArray.size(); i++) {
        JSONObject fieldJson = jsonArray.getJSONObject(i);
        String id = fieldJson.optString("id");
        LogTableField field = transLogTable.findField(id);
        if (field == null) {
          field = transLogTable.getFields().get(i);
        }
        if (field != null) {
          field.setFieldName(fieldJson.optString("name"));
          field.setEnabled(fieldJson.optBoolean("enabled"));
          field.setSubject(StepMeta.findStep(transMeta.getSteps(), fieldJson.optString("subject")));
        }
      }
    }

    jsonObject = JSONObject.fromObject(root.getAttribute("stepLogTable"));
    StepLogTable stepLogTable = transMeta.getStepLogTable();
    stepLogTable.setConnectionName(jsonObject.optString("connection"));
    stepLogTable.setSchemaName(jsonObject.optString("schema"));
    stepLogTable.setTableName(jsonObject.optString("table"));
    stepLogTable.setTimeoutInDays(jsonObject.optString("timeout_days"));
    jsonArray = jsonObject.optJSONArray("fields");
    if (jsonArray != null) {
      for (int i = 0; i < jsonArray.size(); i++) {
        JSONObject fieldJson = jsonArray.getJSONObject(i);
        String id = fieldJson.optString("id");
        LogTableField field = stepLogTable.findField(id);
        if (field == null && i < stepLogTable.getFields().size()) {
          field = stepLogTable.getFields().get(i);
        }
        if (field != null) {
          field.setFieldName(fieldJson.optString("name"));
          field.setEnabled(fieldJson.optBoolean("enabled"));
        }
      }
    }

    jsonObject = JSONObject.fromObject(root.getAttribute("performanceLogTable"));
    PerformanceLogTable performanceLogTable = transMeta.getPerformanceLogTable();
    performanceLogTable.setConnectionName(jsonObject.optString("connection"));
    performanceLogTable.setSchemaName(jsonObject.optString("schema"));
    performanceLogTable.setTableName(jsonObject.optString("table"));
    performanceLogTable.setLogInterval(jsonObject.optString("interval"));
    performanceLogTable.setTimeoutInDays(jsonObject.optString("timeout_days"));
    jsonArray = jsonObject.optJSONArray("fields");
    if (jsonArray != null) {
      for (int i = 0; i < jsonArray.size(); i++) {
        JSONObject fieldJson = jsonArray.getJSONObject(i);
        String id = fieldJson.optString("id");
        LogTableField field = performanceLogTable.findField(id);
        if (field == null && i < performanceLogTable.getFields().size()) {
          field = performanceLogTable.getFields().get(i);
        }
        if (field != null) {
          field.setFieldName(fieldJson.optString("name"));
          field.setEnabled(fieldJson.optBoolean("enabled"));
        }
      }
    }

    jsonObject = JSONObject.fromObject(root.getAttribute("metricsLogTable"));
    MetricsLogTable metricsLogTable = transMeta.getMetricsLogTable();
    metricsLogTable.setConnectionName(jsonObject.optString("connection"));
    metricsLogTable.setSchemaName(jsonObject.optString("schema"));
    metricsLogTable.setTableName(jsonObject.optString("table"));
    metricsLogTable.setTimeoutInDays(jsonObject.optString("timeout_days"));
    jsonArray = jsonObject.optJSONArray("fields");
    if (jsonArray != null) {
      for (int i = 0; i < jsonArray.size(); i++) {
        JSONObject fieldJson = jsonArray.getJSONObject(i);
        String id = fieldJson.optString("id");
        LogTableField field = metricsLogTable.findField(id);
        if (field == null && i < metricsLogTable.getFields().size()) {
          field = metricsLogTable.getFields().get(i);
        }
        if (field != null) {
          field.setFieldName(fieldJson.optString("name"));
          field.setEnabled(fieldJson.optBoolean("enabled"));
        }
      }
    }

    jsonArray = JSONArray.fromObject(root.getAttribute("partitionschemas"));
    for (int i = 0; i < jsonArray.size(); i++) {
      jsonObject = jsonArray.getJSONObject(i);
      PartitionSchema partitionSchema = decodePartitionSchema(jsonObject);
      PartitionSchema check = transMeta.findPartitionSchema(partitionSchema.getName());
      if (check != null) {
        if (!check.isShared()) {
          transMeta.addOrReplacePartitionSchema(partitionSchema);
        }
      } else {
        transMeta.getPartitionSchemas().add(partitionSchema);
      }
    }

    decodeSlaveServers(root, transMeta);

    jsonArray = JSONArray.fromObject(root.getAttribute("clusterSchemas"));
    for (int i = 0; i < jsonArray.size(); i++) {
      jsonObject = jsonArray.getJSONObject(i);
      ClusterSchema clusterSchema = decodeClusterSchema(jsonObject, transMeta.getSlaveServers());
      clusterSchema.shareVariablesWith(transMeta);

      ClusterSchema check = transMeta.findClusterSchema(clusterSchema.getName());
      if (check != null) {
        if (!check.isShared()) {
          transMeta.addOrReplaceClusterSchema(clusterSchema);
        }
      } else {
        transMeta.getClusterSchemas().add(clusterSchema);
      }
    }

    for (int i = 0; i < transMeta.nrSteps(); i++) {
      transMeta.getStep(i).setClusterSchemaAfterLoading(transMeta.getClusterSchemas());
    }

    transMeta.setSizeRowset(Const.toInt(root.getAttribute("size_rowset"), Const.ROWS_IN_ROWSET));
    transMeta.setSleepTimeEmpty(
        Const.toInt(root.getAttribute("sleep_time_empty"), Const.TIMEOUT_GET_MILLIS));
    transMeta.setSleepTimeFull(
        Const.toInt(root.getAttribute("sleep_time_full"), Const.TIMEOUT_PUT_MILLIS));
    transMeta.setUsingUniqueConnections(
        "Y".equalsIgnoreCase(root.getAttribute("unique_connections")));

    transMeta.setFeedbackShown(!"N".equalsIgnoreCase(root.getAttribute("feedback_shown")));
    transMeta.setFeedbackSize(Const.toInt(root.getAttribute("feedback_size"), Const.ROWS_UPDATE));
    transMeta.setUsingThreadPriorityManagment(
        !"N".equalsIgnoreCase(root.getAttribute("using_thread_priorities")));

    transMeta.setCapturingStepPerformanceSnapShots(
        "Y".equalsIgnoreCase(root.getAttribute("capture_step_performance")));
    transMeta.setStepPerformanceCapturingDelay(
        Const.toLong(root.getAttribute("step_performance_capturing_delay"), 1000));
    transMeta.setStepPerformanceCapturingSizeLimit(
        root.getAttribute("step_performance_capturing_size_limit"));

    transMeta.setKey(XMLHandler.stringToBinary(root.getAttribute("key_for_session_key")));
    transMeta.setPrivateKey("Y".equals(root.getAttribute("is_key_private")));

    return transMeta;
  }