Package com.knowgate.datacopy

Source Code of com.knowgate.datacopy.DataStruct

/*
  Copyright (C) 2003  Know Gate S.L. All rights reserved.
                      C/Oña, 107 1º2 28050 Madrid (Spain)

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions
  are met:

  1. Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.

  2. The end-user documentation included with the redistribution,
     if any, must include the following acknowledgment:
     "This product includes software parts from hipergate
     (http://www.hipergate.org/)."
     Alternately, this acknowledgment may appear in the software itself,
     if and wherever such third-party acknowledgments normally appear.

  3. The name hipergate must not be used to endorse or promote products
     derived from this software without prior written permission.
     Products derived from this software may not be called hipergate,
     nor may hipergate appear in their name, without prior written
     permission.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

  You should have received a copy of hipergate License with this code;
  if not, visit http://www.hipergate.org or mail to info@hipergate.org
*/

package com.knowgate.datacopy;

import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.Timestamp;
import java.sql.SQLException;
import java.sql.CallableStatement;
import java.sql.Statement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;

import java.io.IOException;
import java.io.File;
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.StringBufferInputStream;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.StringReader;

import java.lang.ArrayIndexOutOfBoundsException;
import java.lang.ClassNotFoundException;
import java.math.BigDecimal;
import java.util.Vector;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.HashMap;
import java.util.Properties;
import java.util.Enumeration;
import java.util.Set;
import java.util.Iterator;
import org.xml.sax.*;
import org.xml.sax.helpers.*;

import org.apache.oro.text.regex.*;

import com.knowgate.debug.DebugFile;

/**
* <p>Copier for Complex Data Structures stored at database.</p>
* This is not a general purpose module, but a custom class tailored to the
* design constraints of hipergate standard datamodel.
* @author Sergio Montoro Ten
* @version 0.6 alpha
*/
public class DataStruct extends DefaultHandler implements ContentHandler {

  public DataStruct() {
    initMembers();
  } // DataStruct()

  // ----------------------------------------------------------

  public DataStruct(String sPathXMLFile) throws ClassNotFoundException, IllegalAccessException, InstantiationException, IOException, SAXException {
    initMembers();
    parse(sPathXMLFile);
  } // DataStruct()

  // ----------------------------------------------------------

  public DataStruct(String sPathXMLFile, Properties oProps) throws ClassNotFoundException, IllegalAccessException, InstantiationException, IOException, SAXException {
    initMembers();
    parse(sPathXMLFile, oProps);
  } // DataStruct()

  // ----------------------------------------------------------

  private void initMembers() {
    // Cuenta de tablas en la estructura de datos
    cTables = 0;

    // Indicador de si están los cursores preparados
    bOrPrepared = false;
    bTrPrepared = false;

    // Indicador de estado de las conexiones { DISCONNECTED, CONNECTED, REFERENCED }
    iTrStatus = iOrStatus = DISCONNECTED;

    // Vector para los DataRowSets
    DataRowSets = new Vector();
    // Vector de HashMaps con mapeos de nombres de campos
    FieldMaps = new Vector();
    // Vector de HashMaps con valores por defecto para campos que no existan en Origen
    FieldDefs = new Vector();
    // Transformaciones de datos para reemplazo de nulos y nuevos valores
    Transformations = new Vector();
    // Vector con acciones para efectuar antes de empezar la copia de cada Rowset
    Before = new Vector();
    // Vector con acciones para efectuar después de terminar la copia de cada Rowset
    After = new Vector();
    // Mapeo entre valores GUID en origen y campos autonuméricos en destino
    // GuidToIdentityMap = new HashMap(103);
  } // initMembers()

  // ----------------------------------------------------------

  public void setAutoCommit(boolean bAutoCommit) throws SQLException {
    oTrConn.setAutoCommit(bAutoCommit);
  }

  // ----------------------------------------------------------

  public void commit() throws SQLException {
    oTrConn.commit();
  }

  // ----------------------------------------------------------

  public void rollback() throws SQLException {
    oTrConn.rollback();
  }


  // ----------------------------------------------------------

  public void connectOrigin(String sDriver, String sURL, String sUsr, String sPwd, String sSchema) throws SQLException,ClassNotFoundException {
    // Conecta la conexión Origen
    if (DebugFile.trace) DebugFile.writeln ("Begin DataStruct.connectOrigin(" + sDriver + "," + sURL + "," + sUsr + "," + sPwd + ")");

    // Carga el driver JDBC
    Class oDriver = Class.forName(sDriver);

    if (DebugFile.trace) DebugFile.writeln ("  " + sDriver + " JDBC driver loaded");

    oOrConn = DriverManager.getConnection(sURL, sUsr, sPwd);
    iOrStatus = CONNECTED;

    if (DebugFile.trace) DebugFile.writeln ("End DataStruct.connectOrigin()");
  } // connectOrigin()

  // ----------------------------------------------------------

  public void connectTarget(String sDriver, String sURL, String sUsr, String sPwd, String sSchema) throws SQLException,ClassNotFoundException {
    // Conecta la conexión Destino
    if (DebugFile.trace) DebugFile.writeln ("Begin DataStruct.connectTarget(" + sDriver + "," + sURL + "," + sUsr + "," + sPwd + ")");

    // Carga el driver JDBC
    Class oDriver = Class.forName(sDriver);

    if (DebugFile.trace) DebugFile.writeln ("  " + sDriver + " JDBC driver loaded");

    oTrConn = DriverManager.getConnection(sURL, sUsr, sPwd);
    iTrStatus = CONNECTED;

    if (DebugFile.trace) DebugFile.writeln ("End DataStruct.connectTarget()");
  }

  // ----------------------------------------------------------

  public Connection getOriginConnection() {
    return oOrConn;
  }

  // ----------------------------------------------------------

  public Connection getTargetConnection() {
    return oTrConn;
  }

  // ----------------------------------------------------------

  public void setOriginConnection(Connection oConn) {
    // Establece una referencia a una conexión Origen ya existente
    oOrConn = oConn;
    iOrStatus = REFERENCED;
  }

  // ----------------------------------------------------------

  public void setTargetConnection(Connection oConn) {
    // Establece una referencia a una conexión Destino ya existente
    oTrConn = oConn;
    iTrStatus = REFERENCED;
  }

  // ----------------------------------------------------------

  public void clear() throws SQLException {
    // Limpia todas las estructuras internas de datos del DataStruct
    int t;

    if (DebugFile.trace) DebugFile.writeln ("Begin DataStruct.clear()");

    if (bOrPrepared) {
      for (t=0; t<cTables; t++) {
        if (null!=OrStatements[t]) OrStatements[t].close();
        OrStatements[t] = null;
        if (null!=UpStatements[t]) UpStatements[t].close();
        UpStatements[t] = null;
      }
      OrMetaData = null;
      bOrPrepared = false;
    }

    if (bTrPrepared) {
      for (t=0; t<cTables; t++) {
        if (null!=TrStatements[t]) TrStatements[t].close();
        TrStatements[t] = null;
        if (null!=DlStatements[t]) DlStatements[t].close();
        DlStatements[t] = null;
      }
      TrMetaData = null;
      bTrPrepared = false;
    }

    // Cuenta de tablas en la estructura de datos
    cTables = 0;

    if (null!=After) After.clear();
    if (null!=Before) Before.clear();
    if (null!=Transformations) Transformations.clear();
    if (null!=FieldDefs) FieldDefs.clear();
    if (null!=FieldMaps) FieldMaps.clear();
    if (null!=DataRowSets) DataRowSets.clear();

    if (DebugFile.trace) DebugFile.writeln ("End DataStruct.clear()");

  } // clear()

  // ----------------------------------------------------------

  public void disconnectAll() throws SQLException {
    // Cierra todos los cursores y las conexiones
    int t;

    if (DebugFile.trace) DebugFile.writeln ("Begin DataStruct.disconnectAll()");

    clear();

    // Sólo hay que cerrar las conexiones si no son referencias externas
    if (CONNECTED==iOrStatus) { oOrConn.close(); iOrStatus=DISCONNECTED; }
    if (CONNECTED==iTrStatus) { oTrConn.close(); iTrStatus=DISCONNECTED; }

    if (DebugFile.trace) DebugFile.writeln ("End DataStruct.disconnectAll()");
  } // close()

  // ----------------------------------------------------------

  protected DataRowSet getRowSet(int i) {
    return (DataRowSet) DataRowSets.get(i);
  }

  // ----------------------------------------------------------

  protected Object getResult(int iRow, int iCol) {
    return ((Vector) oResults.get(iRow)).get(iCol);
  }

  // ----------------------------------------------------------

  private boolean isEmpty(String sStr) {
    // Devuelve true si sStr=="" ó sStr==null
    if (null==sStr)
      return true;
    else if (0==sStr.length())
      return true;
    else
      return false;
  } // isEmpty()

  // ----------------------------------------------------------

  protected void execCommands(String sTime, int iTable, Object PK[], int cParams)
      throws SQLException,NullPointerException {
    // Ejecuta los comandos <INIT>, <TERM>, <BEFORE> o <AFTER> definidos para este DataStruct
    CallableStatement oCall;
    Statement oStmt;
    ResultSet rCount;
    int cAffected;
    String sSQL;
    String sTable;
    ListIterator oIter;

    if (DebugFile.trace) {
      if (iTable!=-1)
        sTable = getRowSet(iTable).OriginTable;
      else
        sTable = "";
      DebugFile.writeln ("Begin DataStruct.execCommands(" +  sTime + ", " + sTable + ", ..., " + String.valueOf(cParams) + ")");
      DebugFile.incIdent();
    }

    // Seleccionar el iterador para la lista adecudada de comandos
    if (-1==iTable) {
      if (sTime.equals("INIT")) {
        if (null==InitStmts)
          throw new NullPointerException("DataStruct.execCommands() InitStmts list not initialized");
        oIter = InitStmts.listIterator();
      } else {
        if (null==TermStmts)
          throw new NullPointerException("DataStruct.execCommands() TermStmts list not initialized");
        oIter = TermStmts.listIterator();
      }
    }
    else {
      if (sTime.equals("BEFORE"))
        oIter = ((LinkedList)Before.get(iTable)).listIterator();
      else
        oIter = ((LinkedList)After.get(iTable)).listIterator();
    }

    while (oIter.hasNext()) {
      sSQL = oIter.next().toString();

      // Si el SQL empieza por "{" entonces se ejecuta como un procedimiento almacenado
      if (sSQL.startsWith("{") || sSQL.startsWith("k_sp")) {
        if (DebugFile.trace) DebugFile.writeln ("Connection.prepareCall(" + sSQL + ")");
        oCall = oTrConn.prepareCall(sSQL);
        for (int p=0; p<cParams; p++) {
          if (DebugFile.trace) DebugFile.writeln ("CallableStatement.setObject(" + String.valueOf(p+1) + "," + PK[p].toString() + ")");
          oCall.setObject(p+1, PK[p]);
        } // next (p)
        if (DebugFile.trace) DebugFile.writeln ("Connection.execute(" + sSQL + ")");
        oCall.execute();
        oCall.close();
        oCall = null;
      }
      // Si el SQL NO empieza por "{" entonces se ejecuta como un comando sin ResultSet de vuelta
      else {
        oStmt = oTrConn.createStatement();
        if (DebugFile.trace) DebugFile.writeln ("Connection.execute(" + sSQL + ")");
        oStmt.execute(sSQL);
        oStmt.close();
        oStmt = null;
      }
    } // wend

    if (DebugFile.trace) {
      DebugFile.decIdent();
      DebugFile.writeln ("End DataStruct.execCommands()");
    }
  } // execCommands()

  // ----------------------------------------------------------

  public void prepareStatements() throws SQLException {
    // Método para dejar todos los cursores de lectura y escritura preparados
    // Se llama internamente al inicio de los método inser, update o delete

    HashMap oMap;
    String sSQL;
    boolean bIsMapped;
    boolean bHasDefault;
    int iTrCols;
    String sCol;
    int iCol;
    int c;

    if (DebugFile.trace) {
      DebugFile.writeln ("Begin DataStruct.prepareStatements()");
      DebugFile.incIdent();
    }

    oInsertTexts = new HashMap(2*cTables); // Texto SQL de las sentencias Insert
    oSelectTexts = new HashMap(2*cTables); // Texto SQL de las sentencias Select

    OrStatements = new PreparedStatement[cTables]; // Sentencias de lectura
    TrStatements = new PreparedStatement[cTables]; // Sentencias de escritura
    UpStatements = new PreparedStatement[cTables]; // Sentencias de actualización
    DlStatements = new PreparedStatement[cTables]; // Sentencias de borrado

    OrMetaData = new DataTblDef[cTables]; // Metadatos de las tablas de Origen
    TrMetaData = new DataTblDef[cTables]; // Metadatos de las tablas de Destino

    // Recorrer la lista de tablas y preparar los cursores de lectura, escritura y borrado
    for (int s=0; s<cTables; s++) {

      if (CONNECTED==iTrStatus || REFERENCED==iTrStatus) {

        // **************************************
        // Leer la estructura de la tabla destino
        TrMetaData[s] = new DataTblDef();
        if (DebugFile.trace) DebugFile.writeln ("DataTblDef.readMetaData (TargetConnection, " + getRowSet(s).TargetTable + ", " + (String) oToPKs.get(getRowSet(s).TargetTable) + ")");

        // Evitar una excepción Java NullPointerException si no hay PKs en destino
        if (oToPKs.get(getRowSet(s).TargetTable)!=null)
          TrMetaData[s].readMetaData(oTrConn, getRowSet(s).TargetTable, oToPKs.get(getRowSet(s).TargetTable).toString());
        else
          TrMetaData[s].readMetaData(oTrConn, getRowSet(s).TargetTable, null);
        // ***

        // **********************************
        // Preparar las sentencias de borrado
        sSQL = "DELETE FROM " + getRowSet(s).TargetTable;
        if (!isEmpty(getRowSet(s).EraseClause))
          sSQL += " WHERE " + getRowSet(s).EraseClause;
        else
          if (!isEmpty(getRowSet(s).WhereClause))
            sSQL += " WHERE " + getRowSet(s).WhereClause;

        if (DebugFile.trace) DebugFile.writeln ("Connection.prepareStatement(" + sSQL + ")");
        DlStatements[s] = oTrConn.prepareStatement(sSQL);
        // ***

        iTrCols = TrMetaData[s].ColCount;

        // ************************************
        // Preparar las sentencias de inserción
        sSQL = "INSERT INTO " + getRowSet(s).TargetTable + " VALUES (";
        for (c=iTrCols; c>=1; c--)
          sSQL += (c!=1) ? "?," : "?)";

        if (DebugFile.trace) DebugFile.writeln ("Connection.prepareStatement(" + sSQL + ")");

        // Guardar el texto de SQL generado en un HashMap por si luego
        // es preciso recuperarlo usando la tabla de Origen como PK
        oInsertTexts.put (getRowSet(s).OriginTable, sSQL);

        TrStatements[s] = oTrConn.prepareStatement(sSQL);
        // ***

        // ****************************************
        // Preparar las sentencias de actualización
        sSQL = "UPDATE " + getRowSet(s).TargetTable + " SET ";
        for (c=0; c<iTrCols; c++)
          if (!TrMetaData[s].isPrimaryKey(c))
            sSQL += TrMetaData[s].ColNames[c] + "=?,";
        sSQL = sSQL.substring(0, sSQL.length()-1) + " WHERE ";
        for (c=0; c<TrMetaData[s].cPKs; c++)
          sSQL += TrMetaData[s].PrimaryKeys[c] + "=? AND ";
        sSQL = sSQL.substring(0, sSQL.length()-5);

        if (DebugFile.trace) DebugFile.writeln ("Connection.prepareStatement(" + sSQL + ")");
        UpStatements[s] = oTrConn.prepareStatement(sSQL);
        // ***
      } // fi (CONNECTED==iTrStatus)

      if (CONNECTED==iOrStatus || REFERENCED==iOrStatus) {

        // *************************************
        // Leer la estructura de la tabla origen
        OrMetaData[s] = new DataTblDef();
        if (DebugFile.trace) DebugFile.writeln ("DataTblDef.readMetaData (OriginConnection, " + getRowSet(s).OriginTable + ", " + (String) oToPKs.get(getRowSet(s).OriginTable) + ")");
        OrMetaData[s].readMetaData(oOrConn, getRowSet(s).OriginTable, (String) oFromPKs.get(getRowSet(s).OriginTable));

        if (CONNECTED==iTrStatus || REFERENCED==iTrStatus)
          iTrCols = TrMetaData[s].ColCount;
        else
          iTrCols = OrMetaData[s].ColCount;

        if (DebugFile.trace) DebugFile.writeln ("Column count = " + String.valueOf(iTrCols));

        // Preparar las sentencias de lectura
        if (getRowSet(s).FieldList.compareTo("*")!=0) {
          sSQL = "SELECT " + getRowSet(s).FieldList + " ";
        }
        else {
          sSQL = "SELECT ";
          for (c=0; c<iTrCols; c++) {
            // Obtener el nombre en destino de la columna a leer
            sCol = TrMetaData[s].ColNames[c];

            try {
              oMap = (HashMap) FieldMaps.get(s);
              // Si existe un mapeo de nombres,
              // traducir el nombre en destino al que tenga en origen.
              // Tener en cuenta el caso en que la columna destino está
              // definida como autoincremental
              bIsMapped = oMap.containsKey(sCol);
              if (bIsMapped)
                sCol = (String) oMap.get(sCol);
              else {
                bIsMapped = oMap.containsKey(sCol.toUpperCase());
                if (bIsMapped)
                  sCol = (String) oMap.get(sCol.toUpperCase());
                else {
                  bIsMapped = oMap.containsKey(sCol.toLowerCase());
                  if (bIsMapped)
                    sCol = (String) oMap.get(sCol.toLowerCase());
                }
              }
            }
            catch (ArrayIndexOutOfBoundsException e) { bIsMapped=false; }

            // Obtener la posición de la columna en origen
            iCol = OrMetaData[s].findColumnPosition(sCol);
            if (iCol!=-1)
              sSQL += sCol + ((c<iTrCols-1) ? "," : " ");
            else {
              try {
                oMap = (HashMap) FieldDefs.get(s);
                bHasDefault = oMap.containsKey(sCol);
              }
              catch (ArrayIndexOutOfBoundsException e) {
                // Si el XML no tiene una sección <DEFVALS>
                // la llamada FieldDefs.get(s) provocará una
                // excepción ArrayIndexOutOfBoundsException
                bHasDefault = false;
                oMap = null;
              }
              if (bHasDefault)
                // Si la columna no existe en origen mirar si tiene definido valor por defecto
                sSQL += (String) oMap.get(sCol) + " AS " + TrMetaData[s].ColNames[c] + ((c<iTrCols-1) ? "," : " ");
              else
                if (bIsMapped)
                  sSQL += sCol + " AS " + TrMetaData[s].ColNames[c] + ((c<iTrCols-1) ? "," : " ");
                else
                  // Si no tiene valor por defecto leer NULL para luego grabarlo a posteriori
                  sSQL += "NULL AS " + TrMetaData[s].ColNames[c] + ((c<iTrCols-1) ? "," : " ");
            } // fi (iCol!=-1)
          } // next (c)
        } // fi (DataRowSets[s].FieldList=="*")

        sSQL += "FROM " + getRowSet(s).OriginTable;
        if (!isEmpty(getRowSet(s).WhereClause)) {
          if (getRowSet(s).WhereClause.trim().toUpperCase().startsWith("START"))
            sSQL += " " + getRowSet(s).WhereClause;
          else
            sSQL += " WHERE " + getRowSet(s).WhereClause;
        } // fi (isEmpty(getRowSet(s).WhereClause)

        if (DebugFile.trace) DebugFile.writeln ("Connection.prepareStatement(" + sSQL + ")");

        oSelectTexts.put (getRowSet(s).OriginTable, sSQL);

        OrStatements[s] = oOrConn.prepareStatement(sSQL, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
        // ***
      } // end if (CONNECTED==iOrStatus)
    } // end for (s)

    if (CONNECTED==iOrStatus || REFERENCED==iOrStatus) bOrPrepared = true;
    if (CONNECTED==iTrStatus || REFERENCED==iTrStatus) bTrPrepared = true;

    if (DebugFile.trace) {
      DebugFile.decIdent();
      DebugFile.writeln ("End DataStruct.prepareStatements()");
    }
  } // prepareStatements()

  // ----------------------------------------------------------

  public Object convert (Object oValue, int iSQLType) {
    // Función de soporte para hacer castings de tipos entre bases de datos

    Object oRetVal;
    String sClass;

    if (null==oValue) {
      oRetVal = null;
    }
    else {
      sClass = oValue.getClass().getName();

      if (sClass.equals("java.lang.Short")   ||
          sClass.equals("java.lang.Integer") ||
          sClass.equals("java.math.BigDecimal")) {
        if (java.sql.Types.VARCHAR == iSQLType || java.sql.Types.CHAR == iSQLType ||
            java.sql.Types.LONGVARCHAR == iSQLType)
          oRetVal = oValue.toString();
        else if (java.sql.Types.DECIMAL == iSQLType ||
                 java.sql.Types.NUMERIC == iSQLType)
          oRetVal = new BigDecimal(oValue.toString());
        else if (java.sql.Types.INTEGER == iSQLType)
          oRetVal = new Integer(oValue.toString());
        else if (java.sql.Types.SMALLINT == iSQLType)
          oRetVal = new Short(oValue.toString());
        else
          oRetVal = oValue;
      }
      else if (sClass.equals("java.lang.String")) {
        if (java.sql.Types.DECIMAL == iSQLType ||
            java.sql.Types.NUMERIC == iSQLType )
          oRetVal = new BigDecimal(oValue.toString());
        else if (java.sql.Types.SMALLINT == iSQLType)
          oRetVal = new Short(oValue.toString());
        else if (java.sql.Types.INTEGER == iSQLType) {
          String str = oValue.toString();
          oRetVal = new Integer(str);
          }
        else
          oRetVal = oValue;
      }
      else if (sClass.equals("java.sql.Timestamp")) {
        oRetVal = new java.sql.Date(((Timestamp)oValue).getTime());
      }
      else
        oRetVal = oValue;
    }
    return oRetVal;
  } // convert()

  // ----------------------------------------------------------

  public int mapType(int iSQLType) {
    // Mapeo de tipos,
    // actualmente sólo sirve para convertir los TIMESTAMP en DATETIME

    int iRetType;

    switch(iSQLType) {
      case java.sql.Types.TIMESTAMP:
        iRetType = java.sql.Types.DATE;
        break;
      default:
        iRetType = iSQLType;
    }
    return iRetType;
  } // mapType()

  // ----------------------------------------------------------

  /* ESTA FUNCION NO ESTA TESTEADA Y NO FUNCIONA!!!
  public void delete(Object[] TrPK,  int cParams) throws SQLException {

    PreparedStatement oStmt;
    DataTblDef oMDat;
    HashMap oMap;
    int iErsd;

    if (DebugFile.trace) {
      DebugFile.writeln ("Begin DataStruct.delete(TrPK[], " + String.valueOf(cParams) + ")");
      DebugFile.incIdent();
    }

    execCommands("INIT", -1, TrPK, cParams);

    for (int s=cTables-1; s>=0; s++) {
      oMDat = TrMetaData[s];
      oStmt = TrStatements[s];
      for (int p=0;p<cParams; p++)
        oStmt.setObject(p+1, TrPK[p], oMDat.findColumnType(oMDat.PrimaryKeys[p]));
      iErsd = oStmt.executeUpdate();
      if (DebugFile.trace) DebugFile.writeln (String.valueOf(iErsd) + " rows deleted from " + getRowSet(s).TargetTable);
    } // end for (s)

    execCommands("TERM", -1, TrPK, cParams);

    if (DebugFile.trace) {
      DebugFile.decIdent();
      DebugFile.writeln ("End DataStruct.delete()");
    }
  } // delete()
  */

  // ----------------------------------------------------------

  protected void getRows(Object[] OrPK, Object[] TrPK, int cParams, int iTable) throws SQLException {
    // Método interno de soporte para leer un conjunto de final y almacenarlo
    // en una matriz bidimensional de objetos

    int iPK;
    int iFetchBurst = 500; // Tamaño de ráfaga de lectura
    int iSQLType;
    int cTransforms;
    Vector oRow;
    HashMap oTransforms;
    Object oOriginalValue;
    Object oTransformedValue;
    ResultSet oRSet;
    ResultSetMetaData oRDat;
    DataRowSet oDatR;
    String sColName;
    DataTblDef oMDat = OrMetaData[iTable];
    DataTransformation oDatT;
    PreparedStatement oStmt = OrStatements[iTable];
    PreparedStatement oStmt2;

    // Asignar los parametros de la clave primaria para leer valores en origen

    oDatR = getRowSet(iTable);
    // Comprobar primero si existen parámetros en la cláusula WHERE
    if (oDatR.WhereClause!=null) {
      if (oDatR.WhereClause.indexOf("?")>0) {
        for (int p=0;p<cParams; p++) {
          if (DebugFile.trace) DebugFile.writeln ("binding query input parameter " + String.valueOf(p+1));
          oStmt.setObject(p+1, OrPK[p]);
        } // next (p)
      } // fi (oDatR.WhereClause.indexOf("?")>0)
    } // fi (oDatR.WhereClause!=null)

    if (DebugFile.trace) DebugFile.writeln ("PreparedStatement.executeQuery()");

    oRSet = oStmt.executeQuery(); // Ejecutar la query de lectura de registros

    /* Not supported under PostgreSQL 7.3.4
    if (DebugFile.trace) DebugFile.writeln ("ResultSet.setFetchSize(" + String.valueOf(iFetchBurst) + ")");

    oRSet.setFetchSize (iFetchBurst); // Asignar el tamaño de ráfaga de vuelta
    */

    oDatR = null;

    if (DebugFile.trace) {
      if (DataRowSets.get(iTable)!=null)
        DebugFile.writeln ("FieldList=" + getRowSet(iTable).FieldList);
      else
        DebugFile.writeln ("ERROR: getRowSet(" + String.valueOf(iTable) + ") == null");
    }

    // Si se especificó explícitamente una lista de campos a leer,
    // entonces tomar como número de columnas la del Origen,
    // en otro caso tomar como número de columnas las del Destino.
    if (getRowSet(iTable).FieldList.compareTo("*")!=0)
      iCols = oRSet.getMetaData().getColumnCount();
    else
      iCols = TrMetaData[iTable].ColCount;

    if (DebugFile.trace) DebugFile.writeln ("reading " + String.valueOf(iCols) + " columns");

    // Guardar los resultados en una matriz bidimensional almacenada como un vector de filas
    oResults = new Vector(iFetchBurst, iFetchBurst);

    if (DebugFile.trace) DebugFile.writeln ("new Vector(" + String.valueOf(iFetchBurst) + ")");

    iRows = 0;

    try {
      // Obtener una referencia a las transformaciones de datos para el RowSet actual
      oTransforms = (HashMap) Transformations.get(iTable);
      cTransforms = oTransforms.size();
    }
    catch (ArrayIndexOutOfBoundsException e) {
      if (DebugFile.trace) DebugFile.writeln ("table has no transformation replacements");
      oTransforms = null;
      cTransforms = 0;
    }

    if (0 == cTransforms) {
      // Si no hay transformaciones para campos, usar un algoritmo más rápido con menos condiciones
      while (oRSet.next() && iRows<iFetchBurst) {
        iRows++;
        if (DebugFile.trace) DebugFile.writeln ("caching row " + String.valueOf(iRows));
        oRow = new Vector(iCols);
        for (int c=1; c<=iCols; c++)
          oRow.add(oRSet.getObject(c));
        oResults.add(oRow);
      } // wend ()
    }
    else { // Algoritmo con más condiciones para el caso de reemplazo de transformación de datos
      oRDat = oRSet.getMetaData(); // Alias rápido a los metadatos del ResultSet
      while (oRSet.next() && iRows<iFetchBurst) {
        iRows++;
        if (DebugFile.trace) DebugFile.writeln ("caching row " + String.valueOf(iRows));
        // Crear un vector para la fila
        oRow = new Vector(iCols);
        // Recorer cada columna y almacenar su valor en el vector fila
        iPK = 0;
        for (int c=1; c<=iCols; c++) {
          try {
            // Obtener una referencia a la transformación para la columna actual
            // si no hay transformación saltará una excepción y el valor de la
            // columna se asignará en la sección catch()
            sColName = oRDat.getColumnName(c);

            oDatT = (DataTransformation) oTransforms.get(sColName);

            // Asignar el valor transformado del campo
            if (null==oDatT)
              oRow.add(oRSet.getObject(c));
            else {
              oOriginalValue = oRSet.getObject(c);

              oTransformedValue = oDatT.transform(getOriginConnection(),getTargetConnection(), oOriginalValue);

              if (DebugFile.trace) DebugFile.writeln (sColName + " " + oOriginalValue + " transformed to " + (oTransformedValue!=null ? oTransformedValue : "NULL"));

              oRow.add(oTransformedValue);
              }
          }
          catch (ArrayIndexOutOfBoundsException e) {
            oRow.add(oRSet.getObject(c));
          }
        } // next (c)
        oResults.add(oRow);
      } // wend ()
      oRDat = null;
    } // end if (FieldNils[s].size()==0)

    if (DebugFile.trace) DebugFile.writeln ("row count = " + String.valueOf(iRows));

    oRSet.close();
    oRSet = null;
  } // getRows()

  // ----------------------------------------------------------

  public void insert(Object[] OrPK, Object[] TrPK,  int cParams)
    throws SQLException,NullPointerException {
    // Inserta registros del Origen en el Destino,
    // si encuentra un registro duplicado lo actualiza sin dar ningún error,
    // si el registro no está, lo inserta

    String sField;
    DataTblDef oMDat;
    PreparedStatement oInsrt;
    StringReader oReader;
    Object oValue;
    String sValue;
    int r;
    int q;
    int iPK;
    int iSQLType;

    if (DebugFile.trace) {
      DebugFile.writeln ("Begin DataStruct.insert(OrPK[], TrPK[], " + String.valueOf(cParams) + ")");
      DebugFile.incIdent();
    }

    execCommands("INIT", -1, OrPK, cParams);

    // Preparar todos los cursores
    if (!bTrPrepared  || !bTrPrepared) prepareStatements();

    // Iterar sobre las tablas: para cada una de ellas leer sus registros e insertarlos en destino
    for (int s=0; s<cTables; s++) {
      if (DebugFile.trace) DebugFile.writeln ("processing rowset from " + getRowSet(s).OriginTable + " to " + getRowSet(s).TargetTable);

      execCommands("BEFORE", s, OrPK, cParams);

      getRows(OrPK, TrPK, cParams, s); // Modifica {iRows, iCols} como efecto lateral

      oMDat = TrMetaData[s];
      oInsrt = TrStatements[s];

      // Iterar sobre cada fila leida en origen y actualizarla en destino
      for (r=0; r<iRows; r++) {
        iPK = 0;
        // Iterador de parametros de entrada
        for (q=0; q<iCols; q++) {
          sField = oMDat.ColNames[q];
          iSQLType = oMDat.ColTypes[q];
          oValue = getResult(r,q);

          if (oMDat.isPrimaryKey(q)) {
            if (iPK<cParams && oMDat.inheritsPK(TrMetaData[0])) {
              if (null!=TrPK[iPK]) {
                if (oValue.getClass().equals(TrPK[iPK].getClass()) &&
                    oMDat.bestMatch(q, TrMetaData[0], iPK)) {
                  if (DebugFile.trace) DebugFile.writeln ("swaping PK " + oValue.toString() + " to " + TrPK[iPK].toString() + " before insert");
                  oValue = TrPK[iPK];
                } // fi (oValue.getClass() == TrPK[iPK].getClass())
              } // fi (null!=TrPK[iPK])
            iPK++;
            } // fi
          } // fi (oMDat.isPrimaryKey(q))

          if (DebugFile.trace)
            if (oValue!=null)
              DebugFile.writeln ("binding " + sField + "=" + oValue.toString() + " as SQLType " + String.valueOf(iSQLType));
            else
              DebugFile.writeln ("binding " + sField + "=NULL as SQLType " + String.valueOf(iSQLType));

          if (iSQLType==java.sql.Types.LONGVARCHAR) {
            sValue = oValue.toString() " ";
            oReader = new StringReader(sValue);
            oInsrt.setCharacterStream(q+1, oReader, sValue.length()-1);
          }
          else
            oInsrt.setObject(q+1, convert(oValue, iSQLType), mapType(iSQLType));
        } // end for (q)

        if (DebugFile.trace) DebugFile.writeln ("PreparedStatement.execute()");
        oInsrt.execute();
      } // end for (r)

      oResults.clear();
      oResults = null;

      execCommands("AFTER", s, OrPK, cParams);
    } // end for (s)

    execCommands("TERM", -1, OrPK, cParams);

    if (DebugFile.trace) {
      DebugFile.decIdent();
      DebugFile.writeln ("End DataStruct.insert()");
    }
  } // insert

  // ----------------------------------------------------------

  public void update(Object[] OrPK, Object[] TrPK,  int cParams) throws SQLException {
    // Inserta registros del Origen en el Destino,
    // si encuentra un registro duplicado lo actualiza sin dar ningún error,
    // si el registro no está, lo inserta

    String sField;
    DataTblDef oMDat;
    PreparedStatement oInsrt;
    PreparedStatement oUpdt;
    Object oValue;
    String sValue;
    StringReader oReader;
    int r;
    int q;
    int iPK;
    int cUpdated;
    int iSQLType;

    if (DebugFile.trace) {
      DebugFile.writeln ("Begin DataStruct.update(OrPK[], TrPK[], " + String.valueOf(cParams) + ")");
      DebugFile.incIdent();
    }

    execCommands("INIT", -1, OrPK, cParams);

    // Preparar todos los cursores
    if (!bTrPrepared  || !bTrPrepared) prepareStatements();

    // Iterar sobre las tablas: para cada una de ellas leer sus registros e insertarlos en destino
    for (int s=0; s<cTables; s++) {
      if (DebugFile.trace) DebugFile.writeln ("processing rowset from " + getRowSet(s).OriginTable + " to " + getRowSet(s).TargetTable);

      execCommands("BEFORE", s, OrPK, cParams);

      getRows(OrPK, TrPK, cParams, s); // Modifica {iRows, iCols} como efecto lateral

      oMDat = TrMetaData[s];
      oUpdt = UpStatements[s];

      // Iterar sobre cada fila leida en origen y actualizarla en destino
      for (r=0; r<iRows; r++) {
        iPK = 0; // Cuenta de parametros de clave primaria con valor asignado

        if (oMDat.ColCount>oMDat.cPKs) {

          // Iterador de parametros de entrada
          for (q=0; q<iCols; q++) {
            sField = oMDat.ColNames[q];   // Nombre del campo en destino
            iSQLType = oMDat.ColTypes[q]; // Tipo del campo en destino

            if (oMDat.isPrimaryKey(q)) {
              if (iPK<cParams && oMDat.inheritsPK(TrMetaData[0])) {
                if (null!=TrPK[iPK]) {
                  if (getResult(r,q).getClass().equals(TrPK[iPK].getClass()) &&
                      oMDat.bestMatch(q, TrMetaData[0], iPK)) {
                    if (DebugFile.trace) DebugFile.writeln("swaping PK " + getResult(r, q).toString() + " to " + TrPK[iPK].toString() + " before update");
                   oValue = TrPK[iPK];
                  }
                  else {
                    oValue = getResult(r,q);
                  } // fi (getResult(r,q).getClass() == TrPK[iPK].getClass())
                }
                else {
                  oValue = getResult(r, q);
                } // fi (null!=TrPK[iPK])
              }
              else {
                oValue = getResult(r,q);
              } // fi (iPK<cParams && oMDat.inheritsPK(TrMetaData[0])))

              if (DebugFile.trace)
                if (oValue==null)
                  DebugFile.writeln ("binding " + sField + "=null as SQLType " + String.valueOf(iSQLType) + " at parameter " + String.valueOf(iCols-oMDat.cPKs+iPK+1));
                else
                  DebugFile.writeln ("binding " + sField + "=" + oValue.toString() + " as SQLType " + String.valueOf(iSQLType) + " at parameter " + String.valueOf(iCols-oMDat.cPKs+iPK+1));

              oUpdt.setObject(iCols-oMDat.cPKs+iPK+1, convert(oValue, iSQLType), mapType(iSQLType));
              iPK++;
            }
            else {
              if (DebugFile.trace) DebugFile.writeln ("binding " + sField + " as SQLType " + String.valueOf(iSQLType) + " at parameter " + String.valueOf(q+1-iPK));

              if (iSQLType==java.sql.Types.LONGVARCHAR) {
                sValue = getResult(r,q).toString() " ";
                oReader = new StringReader(sValue);
                oUpdt.setCharacterStream(q+1-iPK, oReader, sValue.length()-1);
              }
              else
                oUpdt.setObject(q+1-iPK, convert(getResult(r,q), iSQLType), mapType(iSQLType));
            }
          } // next (q)

          if (DebugFile.trace) DebugFile.writeln ("PreparedStatement.executeUpdate()");
          cUpdated = oUpdt.executeUpdate();

          if (DebugFile.trace) DebugFile.writeln (String.valueOf(cUpdated) + " rows updated");
        }
        else {
          cUpdated = 0;
          if (DebugFile.trace)
            DebugFile.writeln ("pk count=" + String.valueOf(oMDat.cPKs) + " column count=" + String.valueOf(oMDat.ColCount) + " row not updated because no non-pk columns found");
        }
        // fi (oMDat.cPKs>oMDat.ColCount)

        if (0==cUpdated) {
          oInsrt = TrStatements[s];
          iPK = 0;
          // Iterador de parametros de entrada
          for (q=0; q<iCols; q++) {
            sField = oMDat.ColNames[q];
            iSQLType = oMDat.ColTypes[q];
            oValue = getResult(r,q);

            if (oMDat.isPrimaryKey(q)) {
              if (iPK<cParams && oMDat.inheritsPK(TrMetaData[0])) {
                if (null!=TrPK[iPK]) {
                  if (oValue.getClass().equals(TrPK[iPK].getClass()) &&
                      oMDat.bestMatch(q, TrMetaData[0], iPK)) {
                    if (DebugFile.trace) DebugFile.writeln ("swaping PK " + oValue.toString() + " to " + TrPK[iPK].toString());
                    oValue = TrPK[iPK];
                  }
                }
              } // fi (iPK<cParams && oMDat.hasSamePK(TrMetaData[0]))
              iPK++;
            } // fi (oMDat.isPrimaryKey(q))

            if (DebugFile.trace) DebugFile.writeln ("binding " + sField + " as SQLType " + String.valueOf(iSQLType));

            if (iSQLType==java.sql.Types.LONGVARCHAR) {
              sValue = oValue.toString() " ";
              oReader = new StringReader(sValue);
              oInsrt.setCharacterStream(q+1, oReader, sValue.length()-1);
            }
            else
              oInsrt.setObject(q+1, convert(oValue, iSQLType), mapType(iSQLType));
          } // end for (q)

          if (DebugFile.trace) DebugFile.writeln ("PreparedStatement.execute()");
          oInsrt.execute();
        } // end if (cUpdated==0)
      } // end for (r)

      oResults.clear();
      oResults = null;

      execCommands("AFTER", s, OrPK, cParams);
    } // end for (s)

    execCommands("TERM", -1, OrPK, cParams);

    if (DebugFile.trace) {
      DebugFile.decIdent();
      DebugFile.writeln ("End DataStruct.update()");
    }
  } // update

  // ----------------------------------------------------------

  protected int seekReferal(DataTransformation oTransform) {
    DataTransformation oTransformRef;
    HashMap oTransformsRef;
    Set oTransformSet;
    Iterator oSetIterator;
    String sChildTable;
    String sReferedTable = oTransform.ReferedTable;
  int nFound = 0;

    if (DebugFile.trace) {
      DebugFile.writeln ("Begin DataStruct.seekReferal(ReferedTable=" + sReferedTable + ", ReferedField=" + oTransform.ReferedField + ")");
      DebugFile.incIdent();
    }

    for (int r=0; r<DataRowSets.size(); r++) {
      // Si el nombre de la tabla de origen del RowSet explorado
      // coincide con el nombre de la tabla referencia, entonces
      // buscar el campo asociado.
      sChildTable = getRowSet(r).OriginTable;

      if (sChildTable.equalsIgnoreCase(sReferedTable)) {
        oTransformsRef = (HashMap) Transformations.get(r);
        // Recorrer la lista de valores
        oTransformSet = oTransformsRef.keySet();
        oSetIterator = oTransformSet.iterator();
        while (oSetIterator.hasNext()) {
          oTransformRef = (DataTransformation) oTransformsRef.get(oSetIterator.next());
          if (oTransformRef.OriginField.equalsIgnoreCase(oTransform.ReferedField)) {
            oTransform.setReferedValues(oTransformRef);
            nFound++;
            if (DebugFile.trace) DebugFile.writeln (oTransform.OriginTable + "." + oTransformRef.OriginField + " references " + oTransform.ReferedTable + "." + oTransform.ReferedField);
          } // fi (oTransformRef.OriginField == oTransform.ReferedField)
        } // wend()
      } // fi (DataRowSets[r].OriginTable == oTransform.ReferedTable)
    } // next (r)

    if (DebugFile.trace) {
      DebugFile.decIdent();
      DebugFile.writeln ("End DataStruct.seekReferal() : "+String.valueOf(nFound));
    }
    return nFound;
  } // seekReferal

  // ==========================================================

  //
  // ContentHandler methods
  //

  /** Start document. */
  public void startDocument() throws SAXException {

    if (DebugFile.trace) {
      DebugFile.writeln ("Begin DataStruct.startDocument()");
      DebugFile.incIdent();
    }

    fElements = 0;
    fCharacters = 0;
    sContext = "";
    sNode = "";
    oFromPKs = new HashMap (5,3);
    oToPKs = new HashMap (5,3);

    InitStmts = new LinkedList();
    TermStmts = new LinkedList();

    if (DebugFile.trace) {
      DebugFile.decIdent();
      DebugFile.writeln ("End DataStruct.startDocument()");
    }
  } // startDocument()

  // ----------------------------------------------------------

  public void startElement(String uri, String local, String raw,
                           Attributes attrs) throws SAXException {
    fElements++;
    sChars = "";

    if (local.equalsIgnoreCase("ROWSET")) {
      oCurrRowSet = new DataRowSet();
      DataRowSets.add(oCurrRowSet);
      cTables++;

      oCurrMap = new HashMap(13,5);
      FieldMaps.add(oCurrMap);

      oCurrTransform = new HashMap(5,3);
      Transformations.add(oCurrTransform);

      oCurrDef = new HashMap(13,5);
      FieldDefs.add(oCurrDef);

      oCurrBef = new LinkedList();
      Before.add(oCurrBef);

      oCurrAft = new LinkedList();
      After.add(oCurrAft);
    } // fi (local.equalsIgnoreCase("ROWSET"))

    if (local.equalsIgnoreCase("ACTION")   ||
        local.equalsIgnoreCase("MAPPINGS") ||
        local.equalsIgnoreCase("DEFVALS"||
        local.equalsIgnoreCase("NULLVALS") ||
        local.equalsIgnoreCase("BEFORE") ||
        local.equalsIgnoreCase("AFTER") ||
        local.equalsIgnoreCase("INIT") ||
        local.equalsIgnoreCase("TERM") )
      sNode = sContext = local.toUpperCase();
    else
      sNode = local.toUpperCase();

    if ((sNode.equals("MAPPING") && attrs.getLength()>0) ||
        (sNode.equals("DEFVAL") && attrs.getLength()>0))
      sTransform = attrs.getValue(0);
    else
      sTransform = null;

  } // startElement(String,String,StringAttributes)

  // ----------------------------------------------------------

  public void endElement(String uri, String localName, String qname) throws SAXException {
    int    iComma;
    String sOrFld;
    String sOrVal;
    String sTrFld;
    DataTransformation oTransform;

    if (sContext.equalsIgnoreCase("ACTION")) {
      if (sNode.equalsIgnoreCase("FROM"))
        oCurrRowSet.OriginTable = sChars.trim();
      else if (sNode.equalsIgnoreCase("TO"))
        oCurrRowSet.TargetTable = sChars.trim();
      else if (sNode.equalsIgnoreCase("JOIN"))
        oCurrRowSet.JoinTables = sChars;
      else if (sNode.equalsIgnoreCase("WHERE"))
        oCurrRowSet.WhereClause = sChars;
      else if (sNode.equalsIgnoreCase("ERASE"))
        oCurrRowSet.EraseClause = sChars;
      else if (sNode.equalsIgnoreCase("FIELDLIST"))
        oCurrRowSet.FieldList = sChars;
      else if (sNode.equalsIgnoreCase("FROM_PK"))
        oFromPKs.put(oCurrRowSet.OriginTable, sChars.trim());
      else if (sNode.equalsIgnoreCase("TO_PK"))
        oToPKs.put(oCurrRowSet.TargetTable, sChars.trim());
    } // end if (sContext=="ACTION")
    else if (sContext.equalsIgnoreCase("MAPPINGS")) {
      if (sNode.equalsIgnoreCase("MAPPING")) {
        iComma = sChars.lastIndexOf(",");
        sOrFld = sChars.substring(0, iComma).trim();
        sTrFld = sChars.substring(iComma+1).trim();
        oCurrMap.put(sTrFld, sOrFld);

        // Si el elemento <MAPPING> contiene un atributo llamado TRANSFORM
        // entonces crear un nuevo objeto de transformación de datos para este mapeo
        if (null!=sTransform) {
          // Crear un nuevo servicio de transformación de datos para el campo
          oTransform = new DataTransformation(sTransform,
                                              oCurrRowSet.OriginTable, sOrFld,
                                              oCurrRowSet.TargetTable, sTrFld);

          // Asociar el nombre del campo con su transformación de datos
          oCurrTransform.put (sOrFld, oTransform);

      if (DebugFile.trace) DebugFile.writeln("found transformation "+String.valueOf(oTransform.OperationCode)+" for "+sOrFld);

          // Si la transformacion es de tipo REFER,
          // buscar el mapa de valores para la tabla referenciada
          if (oTransform.OperationCode==DataTransformation.Operations.REFER)
            seekReferal(/* inout */ oTransform);
        } // end if (null!=sTransform)
      } // end if (sNode=="MAPPING")
    } // end if (sContext=="MAPPINGS")
    else if (sContext.equalsIgnoreCase("DEFVALS")) {
      if (sNode.equalsIgnoreCase("DEFVAL")) {
        iComma = sChars.indexOf(",");
        sTrFld = sChars.substring(0, iComma).trim();
        sOrFld = sChars.substring(iComma+1).trim();
        oCurrDef.put(sTrFld, sOrFld);
        // Crear un nuevo servicio de transformación de datos para el campo por defecto
        if (null!=sTransform) {
          oTransform = new DataTransformation(sTransform,
                                              oCurrRowSet.OriginTable, sTrFld,
                                              oCurrRowSet.TargetTable, sTrFld);
          // Asociar el nombre del campo con su transformación de datos
          oCurrTransform.put (sTrFld, oTransform);
          // Si la transformacion es de tipo REFER,
          // buscar el mapa de valores para la tabla referenciada
          if (oTransform.OperationCode==DataTransformation.Operations.REFER)
            seekReferal(/* inout */ oTransform);
        } // end if (null!=sTransform)
      } // end if (sNode=="DEFVAL")
    } // end if (sContext=="DEFVALS")
    else if (sContext.equalsIgnoreCase("BEFORE")) {
      if (localName.equalsIgnoreCase("EXEC") ||
          localName.equalsIgnoreCase("CALL"))
        oCurrBef.addLast(sChars);
    } // end if (sContext=="BEFORE")
    else if (sContext.equalsIgnoreCase("AFTER")) {
      if (localName.equalsIgnoreCase("EXEC") ||
          localName.equalsIgnoreCase("CALL"))
        oCurrAft.addLast(sChars);
    } // end if (sContext=="AFTER")
    else if (sContext.equalsIgnoreCase("INIT")) {
      if (localName.equalsIgnoreCase("EXEC") ||
          localName.equalsIgnoreCase("CALL"))
        InitStmts.addLast(sChars);
    } // end if (sContext=="INIT")
    else if (sContext.equalsIgnoreCase("TERM")) {
      if (localName.equalsIgnoreCase("EXEC") ||
          localName.equalsIgnoreCase("CALL"))
        TermStmts.addLast(sChars);
    } // end if (sContext=="TERM")
  } // endElement()

  // ----------------------------------------------------------

  /** Characters. */
  public void characters(char ch[], int start, int length) throws SAXException {
    fCharacters += length;
    sChars += new String(ch,start,length);
  } // characters(char[],int,int);

  // ----------------------------------------------------------

    //
    // ErrorHandler methods
    //

    /** Warning. */
    public void warning(SAXParseException ex) throws SAXException {
        if (DebugFile.trace) DebugFile.write(composeError("Warning", ex));
    } // warning(SAXParseException)

    /** Error. */
    public void error(SAXParseException ex) throws SAXException {
        if (DebugFile.trace) DebugFile.write(composeError("Error", ex));
        throw ex;
    } // error(SAXParseException)

    /** Fatal error. */
    public void fatalError(SAXParseException ex) throws SAXException {
      if (DebugFile.trace) DebugFile.write(composeError("Fatal Error", ex));
      throw ex;
    } // fatalError(SAXParseException)

  // ----------------------------------------------------------

    //
    // Protected methods
    //

    /** Compose the error message. */
    protected String composeError(String type, SAXParseException ex) {
        String sErrDesc = "";
        String systemId = null;
        int index;

        sErrDesc += "[SAX " + type + "] ";

        if (ex==null)
          sErrDesc += "!!!";
        else
          systemId = ex.getSystemId();

        if (systemId != null) {
            index = systemId.lastIndexOf('/');
            if (index != -1) systemId = systemId.substring(index + 1);
            sErrDesc += systemId;
        }

        sErrDesc += " Line:" + ex.getLineNumber();
        sErrDesc += " Column:" + ex.getColumnNumber();
        sErrDesc += " Cause: " + ex.getMessage();
        sErrDesc += "\n";

        return sErrDesc;
    } // composeError(String,SAXParseException)

  // ----------------------------------------------------------

    //
    // Public methods
    //

    public void parse(String sXMLFile) throws InstantiationException,IllegalAccessException,ClassNotFoundException,IOException,SAXException {
      Properties oProps = new Properties();
      parse(sXMLFile, oProps);
    }

    public void parse(String sXMLFile, Properties oProps) throws InstantiationException,IllegalAccessException,ClassNotFoundException,IOException,SAXException {
        // This method parses an XML document into a DataStruct instace

        // local variables
        XMLReader parser;
        Parser sax1Parser;
        File oFile;
        FileReader oFileRead;
        BufferedReader oBuff;
        StringBufferInputStream oStrBuff;
        InputSource ioSrc;
        FileInputStream oStream;
        String sXMLSource;
        String sParam;
        Enumeration oEnum;
        Pattern oPattern;
        PatternMatcher oMatcher = new Perl5Matcher();
        PatternCompiler oCompiler = new Perl5Compiler();
        byte byBuffer[];

        if (DebugFile.trace) {
          DebugFile.writeln ("Begin DataStruct.parse(" + sXMLFile + ")");
          DebugFile.incIdent();
        }

        try {
          if (DebugFile.trace) DebugFile.writeln ("XMLReaderFactory.createXMLReader(" + DEFAULT_PARSER_NAME + ")");

          parser = XMLReaderFactory.createXMLReader(DEFAULT_PARSER_NAME);
        }
        catch (Exception e) {
            if (DebugFile.trace) DebugFile.writeln ("ParserFactory.makeParser(" + DEFAULT_PARSER_NAME + ")");

            sax1Parser = ParserFactory.makeParser(DEFAULT_PARSER_NAME);

            parser = new ParserAdapter(sax1Parser);
            if (DebugFile.trace)
              DebugFile.writeln("warning: Features and properties not supported on SAX1 parsers.");
        }
        try {
          parser.setFeature(NAMESPACES_FEATURE_ID, DEFAULT_NAMESPACES);
          parser.setFeature(VALIDATION_FEATURE_ID, DEFAULT_VALIDATION);
        }
        catch (SAXException e) {
        }

      // parse file
      parser.setContentHandler(this);
      parser.setErrorHandler(this);

      oEnum = oProps.keys();
      if (sXMLFile.startsWith("<?xml")) {
        // replace input parameters
        while (oEnum.hasMoreElements()) {
          sParam = (String) oEnum.nextElement();
          try {
            oPattern = oCompiler.compile("{#" + sParam + "}");
          } catch (MalformedPatternException e) { oPattern=null; }

          sXMLFile = Util.substitute(oMatcher, oPattern,
                                 new Perl5Substitution(oProps.getProperty(sParam), Perl5Substitution.INTERPOLATE_ALL),
                                 sXMLFile, Util.SUBSTITUTE_ALL);
        } // wend()

        oStrBuff = new StringBufferInputStream(sXMLFile);
        ioSrc = new InputSource(oStrBuff);
        parser.parse(ioSrc);
        oStrBuff.close();
      }
      else {
        if (oProps.isEmpty()) {
          oFileRead = new FileReader(sXMLFile);
          oBuff = new BufferedReader(oFileRead, 32767);
          ioSrc = new InputSource(oBuff);
          parser.parse(ioSrc);
          oBuff.close();
          oFileRead.close();
        }
        else {
          oFile = new File(sXMLFile);
          byBuffer = new byte[new Long(oFile.length()).intValue()];

          oStream = new FileInputStream(oFile);
          oStream.read(byBuffer);
          sXMLSource = new String(byBuffer);
          oStream.close();

          while (oEnum.hasMoreElements()) {
            sParam = (String) oEnum.nextElement();
            try {
              oPattern = oCompiler.compile("{#" + sParam + "}");
            } catch (MalformedPatternException e) { oPattern=null; }

            sXMLSource = Util.substitute(oMatcher, oPattern,
                                   new Perl5Substitution(oProps.getProperty(sParam), Perl5Substitution.INTERPOLATE_ALL),
                                   sXMLSource, Util.SUBSTITUTE_ALL);
          } // wend()

          oStrBuff = new StringBufferInputStream(sXMLSource);
          ioSrc = new InputSource(oStrBuff);
          parser.parse(ioSrc);
          oStrBuff.close();
        }
      }

      if (DebugFile.trace) {
        DebugFile.decIdent();
        DebugFile.writeln ("End DataStruct.parse()");
      }
  } // parse()

  // ----------------------------------------------------------

  public void createClassSource(String sPackage, String sSubClassName, String sFile) throws IOException{
    FileWriter oFile = new FileWriter(sFile);
    DataTransformation oDatT;
    Iterator oIter;
    LinkedList oList;
    Object oPKs;
    String sItem;

    oFile.write("package " + sPackage + ";\n");
    oFile.write("import java.util.Vector;\n");
    oFile.write("import java.util.LinkedList;\n");
    oFile.write("import java.util.ListIterator;\n");
    oFile.write("import java.util.HashMap;\n");
    oFile.write("import java.util.Iterator;\n");
    oFile.write("import com.knowgate.datacopy.DataRowSet;\n");
    oFile.write("import com.knowgate.datacopy.DataStruct;\n");
    oFile.write("import com.knowgate.datacopy.DataTransformation;\n");
    oFile.write("\n");

    oFile.write("public class " + sSubClassName + " extends DataStruct {\n");
    oFile.write("  public " + sSubClassName + "() {\n");
    oFile.write("    DataRowSet oRowSet;\n");
    oFile.write("    DataTransformation oTransForm;\n");
    oFile.write("    LinkedList oBefore;\n");
    oFile.write("    LinkedList oAfter;\n");
    oFile.write("    HashMap oMappings;\n");
    oFile.write("    HashMap oDefaults;\n");
    oFile.write("    HashMap oTransforms;\n\n");
    oFile.write("    InitStmts = new LinkedList();\n");
    oFile.write("    TermStmts = new LinkedList();\n");
    oFile.write("    oToPKs = new HashMap();\n");
    oFile.write("    oFromPKs = new HashMap();\n");
    oFile.write("    cTables = " + String.valueOf(DataRowSets.size()) + ";\n");
    oFile.write("\n");

    oIter = InitStmts.listIterator();
    while (oIter.hasNext())
      oFile.write("    InitStmts.addLast(\"" + oIter.next().toString() + "\");\n");
    oFile.write("\n");

    oIter = TermStmts.listIterator();
    while (oIter.hasNext())
      oFile.write("    TermStmts.addLast(\"" + oIter.next().toString() + "\");\n");
    oFile.write("\n");

    for (int c=0;c<cTables;c++) {
      oCurrRowSet  = getRowSet(c);

      oFile.write("    oRowSet = new DataRowSet(\"" + oCurrRowSet.OriginTable + "\",\"" + oCurrRowSet.TargetTable + "\",\"" + oCurrRowSet.JoinTables + "\",\"" + oCurrRowSet.WhereClause + "\",\"" + oCurrRowSet.EraseClause + "\");\n");
      oFile.write("    oRowSet.FieldList = \"" + oCurrRowSet.FieldList.trim() + "\";\n");
      oFile.write("    DataRowSets.add(oRowSet);\n");
      oFile.write("    oBefore = new LinkedList();\n");
      oFile.write("    oAfter = new LinkedList();\n");
      oFile.write("    oMappings = new HashMap();\n");
      oFile.write("    oDefaults = new HashMap();\n");
      oFile.write("    oTransforms = new HashMap();\n");

      oPKs = oFromPKs.get(oCurrRowSet.OriginTable);
      if (null!=oPKs)
        oFile.write("    oFromPKs.put(\"" + oCurrRowSet.OriginTable + "\",\"" + oPKs.toString() + "\");\n");
      oPKs = oToPKs.get(oCurrRowSet.TargetTable);
      if (null!=oPKs)
        oFile.write("    oToPKs.put(\"" + oCurrRowSet.TargetTable + "\",\"" + oPKs.toString() + "\");\n\n");

      oList = (LinkedList) Before.get(c);
      if (oList.size()>0) {
        oIter = oList.iterator();
        while (oIter.hasNext())
          oFile.write("    oBefore.addLast(\"" + oIter.next().toString() + "\");\n");
        oIter = null;
      } // fi (oList.size()>0)
      oList = null;
      oFile.write("    Before.add(oBefore);\n");

      oList = (LinkedList) After.get(c);
      if (oList.size()>0) {
        oIter = oList.iterator();
        while (oIter.hasNext())
          oFile.write("    oAfter.addLast(\"" + oIter.next().toString() + "\");\n");
        oIter = null;
      } // fi (oList.size()>0)
      oList = null;
      oFile.write("    After.add(oAfter);\n");

      try {
        oCurrMap = (HashMap) FieldMaps.get(c);
        oIter = oCurrMap.keySet().iterator();
        while (oIter.hasNext()) {
          sItem = (String) oIter.next();
          oFile.write("    oMappings.put(\"" + sItem + "\",\"" + oCurrMap.get(sItem).toString() + "\");\n");
        } // wend
      } catch (ArrayIndexOutOfBoundsException e) { }

      oFile.write("    FieldMaps.add(oMappings);\n");

      try {
        oFile.write("    Transformations.add(oTransforms);\n");
        oCurrTransform = (HashMap) Transformations.get(c);
        oIter = oCurrTransform.keySet().iterator();
        while (oIter.hasNext()) {
          sItem = oIter.next().toString();
          oDatT = (DataTransformation) oCurrTransform.get(sItem);
          oFile.write("    oTransForm = new DataTransformation(" + String.valueOf(oDatT.OperationCode) + "," +
                      "\"" + oDatT.OriginTable + "\",\"" + oDatT.OriginField + "\"," +
                      "\"" + oDatT.TargetTable + "\",\"" + oDatT.TargetField + "\"," +
                      (null==oDatT.ReferedTable ? "null" : "\"" + oDatT.ReferedTable + "\"") + "," +
                      (null==oDatT.ReferedField ? "null" : "\"" + oDatT.ReferedField + "\"") + "," +
                      (null==oDatT.IfNullValue  ? "null" : "\"" + oDatT.IfNullValue + "\"") + ");\n");
          oFile.write("    oTransforms.put(\"" + sItem + "\", oTransForm);\n");
          if (oDatT.OperationCode==DataTransformation.Operations.REFER) oFile.write("    seekReferal(oTransForm);\n");
        } // wend
      } catch (ArrayIndexOutOfBoundsException e) { }

      try {
        oCurrDef = (HashMap) FieldDefs.get(c);
        oIter = oCurrDef.keySet().iterator();
        while (oIter.hasNext()) {
          sItem = (String) oIter.next();
          oFile.write("    oMappings.put(\"" + sItem + "\",\"" + oCurrDef.get(sItem).toString() + "\");\n");
        } // wend
      } catch (ArrayIndexOutOfBoundsException e) { }

      oFile.write("    FieldDefs.add(oDefaults);\n");

      oFile.write("\n");
    // end for (c)

    oFile.write("  }\n}");

    oFile.close();
    oFile = null;
  } // createClassSource ()

  // ----------------------------------------------------------

  private boolean bOrPrepared; // Switch que indica si están preparados los cursores en Origen
  private boolean bTrPrepared; // Switch que indica si están preparados los cursores en Destino
  private Connection oOrConn;  // Conexión de Origen
  private Connection oTrConn;  // Conexión de Destino
  private int iOrStatus;       // Estado de la Conexión de Origen {CONNECTED|DISCONNECTED|REFERENCED}
  private int iTrStatus;       // Estado de la Conexión de Destino {CONNECTED|DISCONNECTED|REFERENCED}

  protected Vector oResults;   // ResultSet de lectura de registros del Origen
  protected int iCols;         // Variable intermedia para pasar estado del método getRows() a insert() y update()
  protected int iRows;         // Variable intermedia para pasar estado del método getRows() a insert()

  // ---------------------------------------------------------
  // Estructuras de datos cargadas al llamar al método parse()

  protected int cTables;  // Cuenta de tablas en el conjunto de RowSets
  protected Vector FieldMaps; // Vector de HashMaps con los mapeos de campos para cada tabla
  protected Vector FieldDefs; // Vector de HashMaps con los valores por defecto para cada tabla
  protected Vector DataRowSets; // Vector de objetos DataRowSet (uno por tabla)
  protected Vector Before;  // Vector de Acciones BEFORE para cada tabla
  protected Vector After;   // Vector de Acciones AFTER para cada tabla
  protected LinkedList InitStmts; // Vector de Acciones Inicializacion
  protected LinkedList TermStmts; // Vector de Acciones Terminacion
  protected Vector Transformations; // Vector con las transformaciones de valores de campos
  protected HashMap oFromPKs;
  protected HashMap oToPKs;

  // ---------------------------------------------------------------------
  // Estructuras de datos cargadas al llamar al método prepareStatements()

  protected PreparedStatement OrStatements[]; // Cursores de lectura en origen
  protected PreparedStatement TrStatements[]; // Cursores de inserción en destino
  protected PreparedStatement UpStatements[]; // Cursores de actualización en destino
  protected PreparedStatement DlStatements[]; // Cursores de borrado en destino
  protected DataTblDef OrMetaData[]; // Definición de metadatos en origen
  protected DataTblDef TrMetaData[]; // Definición de metadatos en destino
  public HashMap oInsertTexts;
  public HashMap oSelectTexts;

  // ---------------------------------------------------------
  // Variables temporales para el procesamiento de eventos SAX

  private String sChars;       // Buffer de lectura de caracteres para SAX
  private long fElements;
  private long fCharacters;
  private String sTransform;
  private String sContext;
  private String sNode;
  private DataRowSet oCurrRowSet;
  private HashMap oCurrMap;
  private HashMap oCurrDef;
  private HashMap oCurrTransform;
  private LinkedList oCurrBef;
  private LinkedList oCurrAft;

  private static final int DISCONNECTED = 0;
  private static final int CONNECTED = 1;
  private static final int REFERENCED = 2;

  // feature ids

    protected static final String NAMESPACES_FEATURE_ID = "http://xml.org/sax/features/namespaces";
    protected static final String NAMESPACE_PREFIXES_FEATURE_ID = "http://xml.org/sax/features/namespace-prefixes";
    protected static final String VALIDATION_FEATURE_ID = "http://xml.org/sax/features/validation";
    protected static final String SCHEMA_VALIDATION_FEATURE_ID = "http://apache.org/xml/features/validation/schema";
    protected static final String SCHEMA_FULL_CHECKING_FEATURE_ID = "http://apache.org/xml/features/validation/schema-full-checking";
    protected static final String DYNAMIC_VALIDATION_FEATURE_ID = "http://apache.org/xml/features/validation/dynamic";

  // default settings

    protected static final String DEFAULT_PARSER_NAME = "org.apache.xerces.parsers.SAXParser";
    protected static final int DEFAULT_REPETITION = 1;
    protected static final boolean DEFAULT_NAMESPACES = true;
    protected static final boolean DEFAULT_NAMESPACE_PREFIXES = false;
    protected static final boolean DEFAULT_VALIDATION = false;
    protected static final boolean DEFAULT_SCHEMA_VALIDATION = false;
    protected static final boolean DEFAULT_SCHEMA_FULL_CHECKING = false;
    protected static final boolean DEFAULT_DYNAMIC_VALIDATION = false;
    protected static final boolean DEFAULT_MEMORY_USAGE = false;
    protected static final boolean DEFAULT_TAGGINESS = false;
}
TOP

Related Classes of com.knowgate.datacopy.DataStruct

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.