/********************************************************* begin of preamble
**
** Copyright (C) 2003-2010 Software- und Organisations-Service GmbH.
** All rights reserved.
**
** This file may be used under the terms of either the
**
** GNU General Public License version 2.0 (GPL)
**
** as published by the Free Software Foundation
** http://www.gnu.org/licenses/gpl-2.0.txt and appearing in the file
** LICENSE.GPL included in the packaging of this file.
**
** or the
**
** Agreement for Purchase and Licensing
**
** as offered by Software- und Organisations-Service GmbH
** in the respective terms of supply that ship with this file.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
** IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
** THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
** POSSIBILITY OF SUCH DAMAGE.
********************************************************** end of preamble*/
package sos.marshalling;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.math.BigInteger;
import java.sql.ResultSet;
import java.sql.Types;
import sos.connection.SOSConnection;
import sos.connection.SOSMySQLConnection;
import sos.marshalling.SOSImExportTableFieldTypes;
import sos.util.SOSStandardLogger;
/**
* <p>
* Title: SOSExport
* </p>
* <p>
* Description: Exportieren von Daten einer Applikation im XML-Format.
* </p>
* <p>
* Copyright: Copyright (c) 2004
* </p>
* <p>
* Company: SOS-Berlin GmbH
* </p>
*
* @author Titus Meyer
* @version 1.5.5
*/
public class SOSExport {
/**
* <p>
* Title: Query
* </p>
* <p>
* Description: Nimmt einen SQL-Statement mit Name, Schlüsselfeldern,
* Parametern und Abhängigkeiten auf.
* </p>
* <p>
* Copyright: Copyright (c) 2004
* </p>
* <p>
* Company: SOS-Berlin GmbH
* </p>
*
* @author Titus Meyer
* @version 1.0
*/
private class Query {
/** Tagname bzw. Tabellenname zu dem SQL-Statement */
private String _tag = null;
/** ArrayListe der zugehörigen Schlüsselfelder */
private ArrayList _key = new ArrayList();
/** Der Querystring */
private String _query = null;
/**
* ArrayListe der Parameter - Das ? Zeichen wird durch Spalteninhalte,
* die als Parameter angegeben wurden ersetzt
*/
private ArrayList _parameters = new ArrayList();
/** ArrayListe der abhängigen SQL-Statement IDs */
private ArrayList _dependRefs = new ArrayList();
/** ArrayListe der unabhängigen SQL-Statement IDs */
private ArrayList _indepdRefs = new ArrayList();
/** Bearbeitungsstatus des SQL-Statements */
private boolean _done = false;
private boolean dependent = false;
/** Operation die durchgef�hrt wurde: M�gliche Operation ist insert, update oder delete*/
private String _operation = null;
HashMap fieldsKeys = null; //Hilfsvariable: Beim operation delete werden hier Schl�sselfelder eingef�gt
/**
* Konstruktor
*
* @param tag
* Name des klammernden Tags fr Elemente der Abfrage
* (Tabellenname)
* @param key
* Schlüsselfeld - mehrere durch Komma getrennt
* @param query
* SQL-Statement der Abfrage
* @param parameters
* Abfrageparameter, d.i. Felder einer vorhergehenden
* Abfrage, mehrere durch Komma getrennt
* @param dependRef
* Nr. der vorhergehenden Abfrage, die Abfrageparameter
* liefert
*/
public Query(String tag, String key, String query, String parameters,
int dependRef) {
_tag = tag;
_key.addAll(Arrays.asList(key.split(",")));
_query = query;
_parameters.addAll(Arrays.asList(parameters.split(",")));
_dependRefs.add(new Integer(dependRef));
}
/**
* Konstruktor
*
* @param tag
* Name des klammernden Tags für Elemente der Abfrage
* (Tabellenname)
* @param key
* Schlüsselfeld - mehrere durch Komma getrennt
* @param query
* SQL-Statement der Abfrage
* @param parameters
* Abfrageparameter, d.i. Felder einer vorhergehenden Abfrage
* mehrere durch Komma getrennt
*/
public Query(String tag, String key, String query, String parameters)
throws Exception {
_tag = tag;
if (key != null && !key.equals("")) {
_key.addAll(Arrays.asList(key.split(",")));
}
_query = query;
if (parameters != null)
_parameters.addAll(Arrays.asList(parameters.split(",")));
}
/**
* Konstruktor
*
* @param tag
* Name des klammernden Tags für Elemente der Abfrage
* (Tabellenname)
* @param key
* Schlüsselfeld - mehrere durch Komma getrennt
* @param query
* SQL-Statement der Abfrage
*
*
* @param parameters
* Abfrageparameter, d.i. Felder einer vorhergehenden Abfrage
* mehrere durch Komma getrennt
*/
public Query(String tag, String key, String query, String parameters, String operation, HashMap keys4Delete)
throws Exception {
_tag = tag;
if (key != null && !key.equals("")) {
_key.addAll(Arrays.asList(key.split(",")));
}
_query = query;
fieldsKeys = keys4Delete;
_operation = operation;
if (parameters != null)
_parameters.addAll(Arrays.asList(parameters.split(",")));
}
/**
* Liefert die unabhängige Referenz des SQL-Statements an der
* Stelle index zurück - sonst null.
*
* @param index
* Index der Referenzliste
* @return unabhängige Referenz-ID
*/
public Integer getDependRef(int index) {
return (Integer) _dependRefs.get(index);
}
/**
* Liefert die Anzahl der unabhängigen Referenzen des
* SQL-Statements zurück.
*
* @return Anzahl der unabhängigen Referenzen.
*/
public int getDependRefCnt() {
return _dependRefs.size();
}
/**
* Fügt eine unabhängige Referenz-ID der Liste hinzu.
*
* @param dependRef
* ID der Referenz.
*/
public void addDependRef(Integer dependRef) {
_dependRefs.add(dependRef);
}
/**
* Liefert einen String mit der Auflistung der unabhängigen
* Referenzen des SQL-Statements zurück.
*
* @return String der Referenzliste.
*/
public String dependRefToStr() {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < _dependRefs.size(); i++) {
sb.append(_dependRefs.get(i).toString());
if (i < _dependRefs.size() - 1) sb.append(", ");
}
return sb.toString();
}
/**
* Gibt an, ob der SQL-Statement schon verarbeitet wurde.
*
* @return Status
*/
public boolean isDone() {
return _done;
}
/**
* Setzt den Verarbeitungsstatus des SQL-Statements.
*
* @param done
* Status als boolean.
*/
public void setDone(boolean done) {
_done = done;
}
/**
* Liefert die unabhängige Referenz-ID des SQL-Statements an der
* Stelle index - sonst null.
*
* @param index
* Index der Referenz-ID in der Liste.
* @return unabhängige Referenz-ID
*/
public Integer getIndepdRef(int index) {
return (Integer) _indepdRefs.get(index);
}
/**
* Liefert die Anzahl der unabhängigen Referenzen in der Liste.
*
* @return Anzahl der Referenzen.
*/
public int getIndepdRefCnt() {
return _indepdRefs.size();
}
/**
* Fügt eine unabhängige Referenz-ID in die Liste ein.
*
* @param indepdRef
* Referenz-ID
*/
public void addIndepdRef(Integer indepdRef) {
_indepdRefs.add(indepdRef);
}
/**
* Liefert einen String mit der Auflistung der unabhängigen
* Referenzen zurück.
*
* @return String der Referenzliste
*/
public String indepdRefToStr() {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < _indepdRefs.size(); i++) {
sb.append(_indepdRefs.get(i).toString());
if (i < _indepdRefs.size() - 1) sb.append(", ");
}
return sb.toString();
}
/**
* Liefert das Schlüsselfeld des SQL-Statements an der Stelle index
* zurück - sonst null.
*
* @param index
* Index des Schlüsselfeldes in der Liste
* @return Key als String
*/
public String getKey(int index) {
return (String) _key.get(index);
}
/**
* Liefert die Anzahl der Schlüsselfelder in der Liste.
*
* @return Anzahl der Keys
*/
public int getKeyCnt() {
return _key.size();
}
/**
* Fügt ein Schlüsselfeld an die Liste an.
*
* @param key
* Schlüsselfeld
*/
public void addKey(String key) {
_key.add(key);
}
/**
* Liefert einen String mit der Auflistung der Schlüsselfelder
* zurück.
*
* @return String der Schlüsselfelder
*/
public String keysToStr() {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < _key.size(); i++) {
sb.append((String) _key.get(i));
if (i < _key.size() - 1) sb.append(", ");
}
return sb.toString();
}
/**
* Liefert einen Parameter an der Stelle index in der Liste zurück -
* sonst null.
*
* @param index
* Index des Parameters
* @return String des Parameters
*/
public String getParameter(int index) {
return (String) _parameters.get(index);
}
/**
* Liefert die Anzahl der Parameter zurück.
*
* @return Anzahl der Parameter
*/
public int getParameterCnt() {
return _parameters.size();
}
/**
* Fügt einen Parameter an die Parameterliste an.
*
* @param parameter
* String des Parameters
*/
public void addParameter(String parameter) {
_parameters.add(parameter);
}
/**
* Liefert einen String mit der Auflistung der Parameter zurück.
*
* @return String der Parameterliste
*/
public String parametersToStr() {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < _parameters.size(); i++) {
sb.append((String) _parameters.get(i));
if (i < _parameters.size() - 1) sb.append(", ");
}
return sb.toString();
}
/**
* Liefert das SQL-Statement zurück.
*
* @return String des SQL-Statements
*/
public String getQuery() {
return _query;
}
/**
* Speichert das SQL-Statement.
*
* @param query
* SQL-Statement
*/
public void setQuery(String query) {
_query = query;
}
/**
* Liefert den Name des klammernden Tags für Elemente der Abfrage
* zurück.
*
* @return String des Tags
*/
public String getTag() {
return _tag;
}
/**
* Speichert den Name des klammernden Tags für Elemente der
* Abfrage.
*
* @param tag
* String des Tags
*/
public void setTag(String tag) {
_tag = tag;
}
/**
* @return Returns the dependent.
*/
public boolean isDependent() {
return dependent;
}
/**
* @param dependent The dependent to set.
*/
public void setDependent(boolean dependent) {
this.dependent = dependent;
}
public String getOperation() {
return _operation;
}
public void setOperation(String _operation) {
this._operation = _operation;
}
public HashMap getFieldsKeys() {
return fieldsKeys;
}
public void setFieldsKeys(HashMap fieldsKeys) {
this.fieldsKeys = fieldsKeys;
}
}
/**
* <p>
* Title: Queries
* </p>
* <p>
* Description: Eine Liste für Queries.
* </p>
* <p>
* Copyright: Copyright (c) 2004
* </p>
* <p>
* Company: SOS-Berlin GmbH
* </p>
*
* @author Titus Meyer
* @version 1.0
*/
private class Queries {
/** ArrayListe der SQL-Statement Objekte */
private ArrayList _list = new ArrayList();
/**
* Fügt eine SQL-Statement Objekt an die Liste an.
*
* @param query
* Query Objekt
* @throws UnsupportedOperationException
* @throws ClassCastException
* @throws NullPointerException
* @throws Exception
*/
public void add(Query query) throws Exception {
_list.add(query);
}
/**
* Liefert ein Query Objekt an der Position index zurück - sonst
* null.
*
* @param index
* Index des Objektes in der Liste
* @return Query Objekt
* @throws IndexOutOfBoundsException
*/
public Query get(int index) throws IndexOutOfBoundsException {
return (Query) _list.get(index);
}
/**
* Löscht die gesamte Query-Liste.
*
* @throws UnsupportedOperationException
*/
public void clear() throws UnsupportedOperationException {
_list.clear();
}
/**
* Liefert die Anzahl der gespeicherten Query-Objkte zurück.
*
* @return Anzahl der Queries
*/
public int cnt() {
return _list.size();
}
}
/** Export Connection Objekt der Klasse SOSConnection */
private SOSConnection _conn = null;
/** StandardLogger Objekt der Klasse SOSStandardLogger */
private SOSStandardLogger _log = null;
/** Name der exportierenden Applikation */
private String _application = null;
/** Name der Export-Datei */
private String _fileName = null;
/** Name des Tags, das den Export umklammert - default: sos_export */
private String _xmlTagname = "sos_export";
/** Zeichensatz - default: iso-8859-1 */
private String _xmlEncoding = "iso-8859-1";
/** Keynormalisierung: strtolower / strtoupper (default) */
private String _normalizeFieldName = "strtoupper";
/** Tagnormalesierung: strtolower (default) / strtoupper */
private String _normalizeTagName = "strtolower";
/** verwendete Einrückungsstring - default: zwei Leerzeichen */
private String _xmlIndentation = " ";
/** Aktuelle Einrückungsstufe */
private int _xmlIndent = 0;
/** Eine Liste von Query-Objekten, die die SQL-Statements enthalten */
private Queries _queries = new Queries();
/** Index der aktuellen Abfrage */
private int _queryCnt = 0;
/** Rekursionszähler */
private int _rekursionCnt = 0;
/** Zeilenumbruch nach dem Zeichen x fr blobs/clobs */
private int _lineWrap = 254;
/**
* Tabelle zur Konvertierung von Teilbytes in den dazugehörigen
* Hex-Wert
*/
private static char[] _hexChar = { '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
/**
* Konstruktor
*
* @param conn
* Datenbankverbindung der SOSConnection Klasse
* @param fileName
* Datei, in die Exportiert wird. Ist file_name = null, so
* liefert export() das Ergebnis zurück.
* @param application
* Name der Anwendung, die die Klasser verwendet
* @param log
* Logger der SOSStandardLogger Klasse
*/
public SOSExport(SOSConnection conn, String fileName, String application,
SOSStandardLogger log) {
if (conn != null) _conn = conn;
if (fileName != null) _fileName = fileName;
if (application != null) _application = application;
if (log != null) _log = log;
// Wirkt sich nur auf den Oracle Treiber aus - verhindert eine Exception
// bei dem Versuch die Groesse der 4GB grossen blobs/clobs in einen
// Integer
// zu wandeln
System.setProperty("oracledatabasemetadata.get_lob_precision", "false");
}
/**
* Setzt das Verbindungsobjekt.
*
* @param conn
* Datenbankobjekt
*/
public void setConnection(SOSConnection conn) {
_conn = conn;
}
/**
* Setzt das Logger/Debugger-Objekt.
*
* @param log
* Loggerobjekt
*/
public void setLogger(SOSStandardLogger log) {
_log = log;
}
/**
* Setzt den Namen der Applikation - wird im Export-Tag gespeichert.
*
* @param application
* Name
*/
public void setApplication(String application) {
_application = application;
}
/**
* Setzt den Pfad der Datei, in die exportiert werden soll. Ist der Pfad
* leer bzw. null, dann wird das Ergebnis des Exports als String zurück
* geliefert.
*
* @param fileName
* Pfad der Datei
*/
public void setFileName(String fileName) {
_fileName = fileName;
}
/**
* Setzt den Prefix der XML-Tags. Default: sos_export
*
* @param xmlTagname
*/
public void setXMLTagname(String xmlTagname) {
_xmlTagname = xmlTagname;
}
/**
* Setzt die Encoding-Angabe im XML-Header. Default: iso-8859-1
*
* @param xmlEncoding
* Enconding
*/
public void setXMLEncoding(String xmlEncoding) {
_xmlEncoding = xmlEncoding;
}
/**
* Setzt die Normalisierung der Tabellenfeldnamen: {strtolower, strtoupper}.
* Default: strtoupper
*
* @param normalizeFieldName
* Name der Normalisierung
*/
public void setNormalizeFieldName(String normalizeFieldName) {
if (!normalizeFieldName.equalsIgnoreCase("strtolower")
|| !normalizeFieldName.equalsIgnoreCase("strtoupper"))
throw new IllegalArgumentException(
"SOSExport.setNormalizeFieldName: normalizeFielName must be \"strtolower\" or \"strtoupper\"");
_normalizeFieldName = normalizeFieldName;
}
/**
* Setzt die Normalisierung der XML-Tagnamen: {strtolower, strtoupper}.
* Default: strtolower
*
* @param normalizeTagName
* Name der Normalisierung
*/
public void setNormalizeTagName(String normalizeTagName) {
if (!normalizeTagName.equalsIgnoreCase("strtolower")
|| !normalizeTagName.equalsIgnoreCase("strtoupper"))
throw new IllegalArgumentException(
"SOSExport.setNormalizeTagName: normalizeTagName must be \"strtolower\" or \"strtoupper\"");
_normalizeTagName = normalizeTagName;
}
/**
* Setzt den String, der für eine Einrückung verwendet werden soll
* (muss eine gerade Länge besitzen). Default: zwei Leerzeichen
*
* @param indentation
* Einrückungsstring
*/
public void setXMLIndentation(String indentation) {
if ((indentation.length() & 0x1) != 0)
throw new IllegalArgumentException(
"SOSExport.setXMLIndentation: the indentation string must have an even length");
_xmlIndentation = indentation;
}
/**
* Setzt die Zeilenlänge, aber der eine neue Begonnen werden soll
* (Zählt nur für die Hex-Blöcke und muss eine gerade
* Länge haben). Default: 254
*
* @param lineWrap
* Zeilenlänge
*/
public void setLineWrap(int lineWrap) {
if ((lineWrap & 0x1) != 0)
throw new IllegalArgumentException(
"SOSExport.setLineWrap: the line must wrap at an even length");
_lineWrap = lineWrap;
}
/**
* Abhängige Abfrage für den Export registrieren.
*
* @param tag
* Name des klammernden Tags für Elemente der Abfrage -
* Tabellenname
* @param key
* Schlüsselfeld(er) der Tabelle - mehrere durch Komma
* getrennt
* @param query
* SQL-Statement der Abfrage. Bei abhängigen Abfragen wird
* das ? Zeichen durch den Inhalt der in parameter angegebenen
* Felder substituiert.
* @param parameter
* Abfrageparameter - Feldnamen aus vorhergehender Abfrage, deren
* Inhalt in die abhängige Abfrage substituiert wird.
* @param queryId
* Nr. der vorhergehenden Abfrage, die die Abfrageparameter
* liefert
* @return Lfd. Nr. der Abfrage
* @throws java.lang.Exception
*/
public int query(String tag, String key, String query, String parameter,
int queryId) throws Exception {
try {
if (query != null && !query.equals("") && tag != null
&& !tag.equals("")) {
Query obj = new Query(tag, key, query, parameter);
if (queryId>-1){
obj.setDependent(true);
}
// bei zu wenigen parametern -> fehler
if (obj.getParameterCnt() < countStr(query, "?")) { throw new IllegalArgumentException(
"SOSExport.query: too few fields in parameter for substitution in the query"); }
if (_log != null)
_log.debug3("query: tag=" + tag + " key=" + key
+ " query_id=" + queryId + " query_cnt="
+ _queryCnt);
// Abhaengigkeit erstellen
if (queryId >= 0 && queryId < _queries.cnt()) {
_queries.get(queryId).addDependRef(new Integer(_queryCnt));
} else if (_queryCnt > 0 && (_queryCnt - 1) < _queries.cnt()) {
_queries.get(_queryCnt - 1).addDependRef(
new Integer(_queryCnt));
} else if (parameter != null) { throw new IllegalArgumentException(
"SOSExport.query: query_id index out of range: "
+ queryId); }
// Abfrage einfuegen
_queries.add(obj);
return _queryCnt++;
} else {
throw new IllegalArgumentException(
"SOSExport.query: empty query statement!");
}
} catch (Exception e) {
throw new Exception("SOSExport.query: " + e.getMessage(), e);
}
}
/**
* Abhängige Abfrage für den Export registrieren.
*
* @param tag
* Name des klammernden Tags für Elemente der Abfrage -
* Tabellenname
* @param key
* Schlüsselfeld(er) der Tabelle - mehrere durch Komma
* getrennt
* @param query
* SQL-Statement der Abfrage. Bei abhängigen Abfragen wird
* das ? Zeichen durch den Inhalt der in parameter angegebenen
* Felder substituiert.
* @param parameter
* Abfrageparameter - Feldnamen aus vorhergehender Abfrage, deren
* Inhalt in die abhängige Abfrage substituiert wird.
* @param queryId
* Nr. der vorhergehenden Abfrage, die die Abfrageparameter
* liefert
*
* @param operation
* welche operation wurde durchgef�hrt? insert, update oder delete
*
* @return Lfd. Nr. der Abfrage
* @throws java.lang.Exception
*/
public int query(String tag, String key, String query, String parameter, String operation, HashMap keys4Delete, int queryId) throws Exception {
try {
if (query != null && !query.equals("") && tag != null
&& !tag.equals("")) {
Query obj = new Query(tag, key, query, parameter, operation, keys4Delete);
//Query obj = new Query(tag, key, query, parameter);
if (queryId>-1){
obj.setDependent(true);
}
// bei zu wenigen parametern -> fehler
if (obj.getParameterCnt() < countStr(query, "?")) { throw new IllegalArgumentException(
"SOSExport.query: too few fields in parameter for substitution in the query"); }
if (_log != null)
_log.debug3("query: tag=" + tag + " key=" + key
+ " query_id=" + queryId + " query_cnt="
+ _queryCnt);
// Abhaengigkeit erstellen
if (queryId >= 0 && queryId < _queries.cnt()) {
_queries.get(queryId).addDependRef(new Integer(_queryCnt));
} else if (_queryCnt > 0 && (_queryCnt - 1) < _queries.cnt()) {
_queries.get(_queryCnt - 1).addDependRef(
new Integer(_queryCnt));
} else if (parameter != null) { throw new IllegalArgumentException(
"SOSExport.query: query_id index out of range: "
+ queryId); }
// Abfrage einfuegen
_queries.add(obj);
return _queryCnt++;
} else {
throw new IllegalArgumentException(
"SOSExport.query: empty query statement!");
}
} catch (Exception e) {
throw new Exception("SOSExport.query: " + e.getMessage(), e);
}
}
/**
* Abhängige Abfrage für den Export registrieren.
*
* @param tag
* Name des klammernden Tags für Elemente der Abfrage -
* Tabellenname
* @param key
* Schlüsselfeld(er) der Tabelle - mehrere durch Komma
* getrennt
* @param query
* SQL-Statement der Abfrage. Bei abhängigen Abfragen wird
* das ? Zeichen durch den Inhalt der in parameter angegebenen
* Felder substituiert.
* @return Lfd. Nr. der Abfrage
* @throws java.lang.Exception
*/
public int query(String tag, String key, String query) throws Exception {
return this.query(tag, key, query, null, -1);
}
/**
* Unabhängige Unterabfrage für Export hinzufügen.
*
* @param tag
* Name des klammernden Tags für Elemente der Abfrage -
* Tabellenname
* @param key
* Schlüsselfeld(er) der Tabelle - mehrere durch Komma
* getrennt
* @param query
* SQL-Statement der Abfrage. Bei unabhängigen Abfragen wird
* das ? Zeichen durch den Inhalt der in parameter angegebenen
* Felder substituiert.
* @param parameter
* Abfrageparameter - Feldnamen aus vorhergehender Abfrage, deren
* Inhalt in die unabhängige Abfrage substituiert wird.
* @param queryId
* Nr. der vorhergehenden Abfrage, die die Abfrageparameter
* liefert
* @return Lfd. Nr. der Abfrage
* @throws java.lang.Exception
*/
public int add(String tag, String key, String query, String parameter,
int queryId) throws Exception {
try {
if (query != null && !query.equals("") && tag != null
&& !tag.equals("")) {
Query obj = new Query(tag, key, query, parameter);
// bei zu wenigen parametern -> fehler
if (obj.getParameterCnt() < countStr(query, "?")) { throw new IllegalArgumentException(
"SOSExport.query: too few fields in parameter for substitution in the query"); }
if (_log != null)
_log.debug3("add: tag=" + tag + " key=" + key
+ " query_id=" + queryId + "query_cnt="
+ _queryCnt);
if (queryId >= 0 && queryId < _queries.cnt()) {
_queries.get(queryId).addIndepdRef(new Integer(_queryCnt));
} else if (parameter != null) {
throw new IllegalArgumentException("SOSExport.add: query_id index out of range: "+ queryId); }
_queries.add(obj);
return _queryCnt++;
} else {
throw new IllegalArgumentException(
"SOSExport.query: tag and query must be defined!");
}
} catch (Exception e) {
throw new Exception("SOSExport.add: " + e.getMessage(), e);
}
}
/**
* Unabhängige Unterabfrage für Export hinzufügen.
*
* @param tag
* Name des klammernden Tags für Elemente der Abfrage -
* Tabellenname
* @param key
* Schlüsselfeld(er) der Tabelle - mehrere durch Komma
* getrennt
* @param query
* SQL-Statement der Abfrage. Bei unabhängigen Abfragen wird
* das ? Zeichen durch den Inhalt der in parameter angegebenen
* Felder substituiert.
* @param parameter
* Abfrageparameter - Feldnamen aus vorhergehender Abfrage, deren
* Inhalt in die unabhängige Abfrage substituiert wird.
*
* @param operation
* welche operation wurde durchgef�hrt? insert, update oder delete
*
* @param queryId
* Nr. der vorhergehenden Abfrage, die die Abfrageparameter
* liefert
* @return Lfd. Nr. der Abfrage
* @throws java.lang.Exception
*/
public int add(String tag, String key, String query, String parameter, String operation, HashMap keys4Delete,
int queryId) throws Exception {
try {
if (query != null && !query.equals("") && tag != null
&& !tag.equals("")) {
Query obj = new Query(tag, key, query, parameter, operation, keys4Delete);
//Query obj = new Query(tag, key, query, parameter);
// bei zu wenigen parametern -> fehler
if (obj.getParameterCnt() < countStr(query, "?")) { throw new IllegalArgumentException(
"SOSExport.query: too few fields in parameter for substitution in the query"); }
if (_log != null)
_log.debug3("add: tag=" + tag + " key=" + key
+ " query_id=" + queryId + "query_cnt="
+ _queryCnt);
if (queryId >= 0 && queryId < _queries.cnt()) {
_queries.get(queryId).addIndepdRef(new Integer(_queryCnt));
} else if (parameter != null) {
throw new IllegalArgumentException("SOSExport.add: query_id index out of range: "+ queryId); }
_queries.add(obj);
return _queryCnt++;
} else {
throw new IllegalArgumentException(
"SOSExport.query: tag and query must be defined!");
}
} catch (Exception e) {
throw new Exception("SOSExport.add: " + e.getMessage(), e);
}
}
/**
* Export anhand der registrierten Abfragen ausführen.
*
* @return Leerer String bei file_name != null, sonst Inhalt des Exports
* @throws java.lang.Exception,
* java.io.FileNotFoundException
*/
public String doExport() throws Exception, FileNotFoundException {
try {
if (_normalizeFieldName.equalsIgnoreCase("strtoupper")) {
_conn.setKeysToUpperCase();
_conn.setFieldNameToUpperCase(true);
} else {
_conn.setKeysToLowerCase();
_conn.setFieldNameToUpperCase(false);
}
// Datei pruefen
if (_fileName != null && !_fileName.equals("")) {
File file = new File(_fileName);
file.createNewFile();
if (!file.canWrite()) { throw new FileNotFoundException(
"File not writeable: " + _fileName); }
if (_log != null) _log.debug2("Starte Export in die Datei...");
SimpleDateFormat dateFormat = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss");
//FileWriter fw = new FileWriter(_fileName);
FileOutputStream fos = new FileOutputStream(_fileName);
OutputStreamWriter fw = new OutputStreamWriter(fos,_xmlEncoding);
// XML Header
fw.write("<?xml version=\"1.0\" encoding=\"" + _xmlEncoding
+ "\"?>\n");
fw.write(indent(1) + "<" + normalizeTagName(_xmlTagname)
+ " application=\"" + _application + "\" created=\""
+ dateFormat.format(new Date()) + "\">\n");
dateFormat = null;
// Abfragen ausfuehren
for (int i = 0; i < _queries.cnt(); i++) {
if (_queries.get(i).isDone() == false && !_queries.get(i).isDependent()) {
if(_queries.get(i).getOperation() != null && _queries.get(i).getOperation().equalsIgnoreCase("delete")) {
exportQueriesForDelete(i,null, fw);
} else {
exportQueries(i, fw);
}
}
}
fw.write(indent(-1) + "</" + normalizeTagName(_xmlTagname)
+ ">\n");
fw.close();
fos.close();
if (_log != null)
_log.debug2("...Export in die Datei beendet");
return "";
}// if file
else {
if (_log != null) _log.debug2("Starte Export...");
StringBuffer output = new StringBuffer();
SimpleDateFormat dateFormat = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss");
// XML Header
output.append("<?xml version=\"1.0\" encoding=\""
+ _xmlEncoding + "\"?>\n");
output.append(indent(1) + "<" + normalizeTagName(_xmlTagname)
+ " application=\"" + _application + "\" created=\""
+ dateFormat.format(new Date()) + "\">\n");
dateFormat = null;
// Abfragen ausfuehren
for (int i = 0; i < _queries.cnt(); i++) {
if (_queries.get(i).isDone() == false) {
output.append(exportQueries(i));
}
}
output.append(indent(-1) + "</" + normalizeTagName(_xmlTagname)
+ ">\n");
// Ergebnis zurueck liefern
if (_log != null) _log.debug2("...Export beendet");
return output.toString();
}
} catch (Exception e) {
throw new Exception("SOSExport.export: " + e.getMessage(), e);
}
}
/**
* Export anhand der registrierten Abfragen ausführen.
*
* @param conn
* Datenbankverbindung der SOSConnection Klasse
* @param fileName
* Datei, in die Exportiert wird. Wenn file_name == null, dann
* wird das Ergebnis zurück gegeben.
* @return leerer String bei einer Datei - sonst Inhalt des Exports
* @throws java.lang.Exception,
* java.io.FileNotFoundException
*/
public String doExport(SOSConnection conn, String fileName)
throws Exception, FileNotFoundException {
_conn = conn;
_fileName = fileName;
return doExport();
}
/**
* Rekursiver Export einer Abfrage mit deren Unterabfragen als String
* bilden.
*
* @param queryId
* Nr. der aktuellen Abfrage
* @return XML Export als String
* @throws java.lang.Exception
*/
private String exportQueries(int queryId) throws Exception {
return exportQueries(queryId, new ArrayList());
}
/**
* Rekursiver Export einer Abfrage mit deren Unterabfragen gleich in eine
* Datei schreiben.
*
* @param queryId
* Nr. der aktuellen Abfrage
* @param fw
* FileWriter Objekt zum Schreiben in eine Datei
* @return XML Export als String
* @throws java.lang.Exception
*/
private String exportQueries(int queryId, Writer fw) throws Exception {
return exportQueries(queryId, new ArrayList(), fw);
}
/**
* Rekursiver Export einer Abfrage mit deren Unterabfragen gleich in eine
* Datei schreiben.
*
* @param queryId
* Nr. der aktuellen Abfrage
* @param parameterValues
* Substitutionswerte für den SQL-Statement
* @param fw
* FileWriter Objekt zum Schreiben in eine Datei
* @return Leerstring
* @throws java.lang.Exception
*/
private String exportQueries(int queryId, ArrayList parameterValues,
Writer fw) throws Exception {
try {
if (_log != null) {
_log.debug3("export_queries: " +
" name=\"" + _queries.get(queryId).getTag() +
"\" query_id=\"" + queryId +
"\" key=\"" + _queries.get(queryId).keysToStr() +
"\" dependend=\"" + _queries.get(queryId).dependRefToStr() +
"\" operation=\"" + _queries.get(queryId).getOperation() +
"\" independend=\"" + _queries.get(queryId).indepdRefToStr() + "\"");
}
_rekursionCnt++;
// Parameterwerte in das SQL-Statement einfuegen
String queryStm = substituteQuery(_queries.get(queryId).getQuery(),
parameterValues);
HashMap allFieldNames = prepareGetFieldName(queryStm);
// Feldinformationen abrufen
SOSImExportTableFieldTypes fieldTypes = getFieldTypes(queryStm
.toString());
// Daten abrufen
ArrayList result = new ArrayList();
result = getArray(queryStm.toString());
fw.write(indent(1) + "<"
+ normalizeTagName(_xmlTagname + "_package id=\"")
+ _queries.get(queryId).getTag() + "\">\n");
if (!result.isEmpty()) {
//// META START ////
fw.write(indent(1) + "<"
+ normalizeTagName(_xmlTagname + "_meta") + ">\n");
fw.write(indent(0) + "<" + normalizeTagName("table name=\"")
+ _queries.get(queryId).getTag() + "\" />\n");
// Key-Felder
fw.write(indent(1) + "<" + normalizeTagName("key_fields")
+ ">\n");
for (int i = 0; i < _queries.get(queryId).getKeyCnt(); i++) {
if (_log != null) {
_log.debug6("key_field[" + i + "]=\""
+ _queries.get(queryId).getKey(i) + "\"");
}
fw.write(indent()
+ "<"
+ normalizeTagName("field name=\"")
+ normalizeFieldName(_queries.get(queryId)
.getKey(i)) + "\"");
fw.write(" type=\""
+ fieldTypes
.getTypeName(normalizeFieldName(_queries
.get(queryId).getKey(i))) + "\"");
fw.write(" typeID=\""
+ fieldTypes.getTypeId(normalizeFieldName(_queries
.get(queryId).getKey(i))) + "\"");
fw.write(" len=\""
+ fieldTypes.getLength(normalizeFieldName(_queries
.get(queryId).getKey(i))) + "\"");
fw.write(" scale=\""
+ fieldTypes.getScale(normalizeFieldName(_queries
.get(queryId).getKey(i))) + "\"");
fw.write(" />\n");
}
fw.write(indent(-1) + normalizeTagName("</key_fields>") + "\n");
// Felder
fw.write(indent(1) + normalizeTagName("<fields>") + "\n");
Object[] fields = ((HashMap) result.get(0)).keySet().toArray();
for (int i = 0; i < fields.length; i++) {
fw.write(indent() + "<" + normalizeTagName("field name=\"")
+ normalizeFieldName((String) fields[i]) + "\"");
fw
.write(" type=\""
+ fieldTypes
.getTypeName(normalizeFieldName((String) fields[i]))
+ "\"");
fw
.write(" typeID=\""
+ fieldTypes
.getTypeId(normalizeFieldName((String) fields[i]))
+ "\"");
fw
.write(" len=\""
+ fieldTypes
.getLength(normalizeFieldName((String) fields[i]))
+ "\"");
fw
.write(" scale=\""
+ fieldTypes
.getScale(normalizeFieldName((String) fields[i]))
+ "\"");
fw.write(" />\n");
}
fields = null;
fw.write(indent(-1) + normalizeTagName("</fields>") + "\n");
fw.write(indent(-1) + "</"
+ normalizeTagName(_xmlTagname + "_meta") + ">\n");
//// META END ////
// Records schreiben
fw.write(indent(1) + "<"
+ normalizeTagName(_xmlTagname + "_data") + ">\n");
// Zeilen
for (int i = 0; i < result.size(); i++) {
HashMap record = (HashMap) result.get(i);
if (_log != null) {
_log.debug9("get: " + _queries.get(queryId).getTag()
+ " query_id=" + queryId);
}
fw.write(indent(1) + "<"
+ normalizeTagName(_xmlTagname + "_record name=\"")
+ _queries.get(queryId).getTag() + "\">\n");
fw
.write(indent(1) +
"<" + normalizeTagName(_xmlTagname + "_fields") +
(_queries.get(queryId).getOperation() != null && _queries.get(queryId).getOperation().length() > 0
? " operation=\"" + _queries.get(queryId).getOperation() + "\" "
: "") +
">\n");
// Spalten alphabetische Sortierung
//Vector record_vector = new Vector(record.keySet());
//Collections.sort(record_vector);
for (Iterator it = record.keySet().iterator(); it.hasNext();) {
String key = it.next().toString();
String lobType = null;
switch (fieldTypes.getTypeId(normalizeFieldName(key))) {
case Types.LONGVARCHAR:
lobType = "clob";
case Types.BINARY:
if (lobType == null) lobType = "blob";
case Types.BLOB:
if (lobType == null) lobType = "blob";
case Types.CLOB:
if (lobType == null) lobType = "clob";
case Types.LONGVARBINARY:
if (lobType == null) lobType = "blob";
case Types.VARBINARY:
if (lobType == null) lobType = "blob";
//// als binaer behandeln und in hex umwandeln ////
// create blob-stm
int posBegin = new String(queryStm).toLowerCase()
.indexOf("from");
int posEnd = new String(queryStm).toLowerCase()
.indexOf(" ", posBegin + 5);
StringBuffer queryBlobStm = new StringBuffer();
String blobFieldName = getBlobFieldName(allFieldNames, key
.toString());
queryBlobStm.append("SELECT "
+ normalizeFieldName(blobFieldName) + " ");
if (posEnd < posBegin) posEnd = queryStm.length();
queryBlobStm.append(queryStm.substring(posBegin,
posEnd));
String and = " WHERE ";
for (int j = 0; j < _queries.get(queryId)
.getKeyCnt(); j++) {
String keyFieldName = getKeyFieldName(allFieldNames,
_queries.get(queryId).getKey(j));
//queryBlobStm.append(and + "\""+
// normalizeFieldName(_queries.get(queryId).getKey(j))
// + "\" =");
queryBlobStm.append(and
+ normalizeFieldName(keyFieldName)
+ " =");
queryBlobStm
.append(quote(
fieldTypes
.getTypeId(normalizeFieldName(_queries
.get(queryId)
.getKey(j))),
(String) record
.get(normalizeFieldName(_queries
.get(queryId)
.getKey(j)))));
and = " AND ";
}
// blob mit Umbruch ausgeben
byte[] blob = null;
if (lobType.equals("blob")) {
blob = _conn.getBlob(queryBlobStm.toString());
} else {
blob = str2bin(_conn.getClob(queryBlobStm
.toString()));
}
fw.write(indent() + "<" + normalizeTagName(key)
+ " null=");
if (blob != null && blob.length > 0) {
indent(1);
//original
//fw.write("\"false\">\n"+ toHexString(blob, indent(), _lineWrap) + "\n"+ indent(-1));
fw.write("\"false\">\n");
toHexString(blob, indent(), _lineWrap ,fw);
fw.write("\n"+ indent(-1));
} else {
fw.write("\"true\">");
}
fw.write("</" + normalizeTagName(key) + ">\n");
break;
// ...sonst als xml string ausgeben
default:
// TODO Workaround - Millisekunden entfernen
if (record.get(key) != null) {
switch (fieldTypes
.getTypeId(normalizeFieldName(key))) {
case Types.DATE:
case Types.TIMESTAMP:
String val = record.get(key).toString();
if (val.endsWith(".0")) {
record.put(key, val.substring(0, val
.length() - 2));
}
}
}
fw.write(indent() + "<" + normalizeTagName(key)
+ " null=");
if (record.get(key) != null)
fw.write("\"false\"><![CDATA["
+ asXml(record.get(key).toString())
+ "]]>");
else
fw.write("\"true\"><![CDATA[]]>");
fw.write("</" + normalizeTagName(key) + ">\n");
} // switch
} // iteration Fields
fw
.write(indent(-1) + "</"
+ normalizeTagName(_xmlTagname + "_fields")
+ ">\n");
// Rekursion independend refs
if (_queries.get(queryId).getIndepdRefCnt() > 0) {
for (int j = 0; j < _queries.get(queryId)
.getIndepdRefCnt(); j++) {
int recQuery = _queries.get(queryId)
.getIndepdRef(j).intValue();
if (_log != null)
_log
.debug6("recursive independend query: "
+ _queries.get(recQuery)
.getQuery());
exportQueries(recQuery, queryParams(recQuery,
record), fw);
}
}
// Rekursion dependend refs
if (_queries.get(queryId).getDependRefCnt() > 0) {
for (int j = 0; j < _queries.get(queryId)
.getDependRefCnt(); j++) {
int recQuery = _queries.get(queryId)
.getDependRef(j).intValue();
if (_log != null)
_log
.debug6("recursive dependend query: "
+ _queries.get(recQuery)
.getQuery());
exportQueries(recQuery, queryParams(recQuery,
record), fw);
}
}
fw
.write(indent(-1) + "</"
+ normalizeTagName(_xmlTagname + "_record")
+ ">\n");
} // iteration Records
fw.write(indent(-1) + "</"
+ normalizeTagName(_xmlTagname + "_data") + ">\n");
} // if results
fw.write(indent(-1) + "</"
+ normalizeTagName(_xmlTagname + "_package") + ">\n");
_queries.get(queryId).setDone(true);
return "";
} catch (Exception e) {
throw new Exception("SOSExport.exportQueries: " + e.getMessage(), e);
}
}
/**
* Rekursiver Export einer Abfrage mit deren Unterabfragen gleich in eine
* Datei schreiben.
*
* @param queryId
* Nr. der aktuellen Abfrage
* @param parameterValues
* Substitutionswerte für den SQL-Statement
* @param fw
* FileWriter Objekt zum Schreiben in eine Datei
* @return Leerstring
* @throws java.lang.Exception
*/
public String exportQueriesForDelete(int queryId, ArrayList parameterValues,
Writer fw) throws Exception {
try {
if (_log != null) {
_log.debug3("export_queries: " +
" name=\"" + _queries.get(queryId).getTag() +
"\" query_id=\"" + queryId +
"\" key=\"" + _queries.get(queryId).keysToStr() +
"\" dependend=\"" + _queries.get(queryId).dependRefToStr() +
"\" operation=\"" + _queries.get(queryId).getOperation() +
"\" field_keys=\"" + _queries.get(queryId).getFieldsKeys() +
"\" independend=\"" + _queries.get(queryId).indepdRefToStr() + "\"");
}
_rekursionCnt++;
// Parameterwerte in das SQL-Statement einfuegen
String queryStm = substituteQuery(_queries.get(queryId).getQuery(),
parameterValues);
HashMap allFieldNames = prepareGetFieldName(queryStm);
// Feldinformationen abrufen
SOSImExportTableFieldTypes fieldTypes = getFieldTypes(queryStm
.toString());
fw.write(indent(1) + "<"
+ normalizeTagName(_xmlTagname + "_package id=\"")
+ _queries.get(queryId).getTag() + "\">\n");
//// META START ////
fw.write(indent(1) + "<"
+ normalizeTagName(_xmlTagname + "_meta") + ">\n");
fw.write(indent(0) + "<" + normalizeTagName("table name=\"")
+ _queries.get(queryId).getTag() + "\" />\n");
// Key-Felder
fw.write(indent(1) + "<" + normalizeTagName("key_fields")
+ ">\n");
for (int i = 0; i < _queries.get(queryId).getKeyCnt(); i++) {
if (_log != null) {
_log.debug6("key_field[" + i + "]=\""
+ _queries.get(queryId).getKey(i) + "\"");
}
fw.write(indent()
+ "<"
+ normalizeTagName("field name=\"")
+ normalizeFieldName(_queries.get(queryId).getKey(i)) + "\"");
fw.write(" type=\""
+ fieldTypes
.getTypeName(normalizeFieldName(_queries
.get(queryId).getKey(i))) + "\"");
fw.write(" typeID=\""
+ fieldTypes.getTypeId(normalizeFieldName(_queries
.get(queryId).getKey(i))) + "\"");
fw.write(" len=\""
+ fieldTypes.getLength(normalizeFieldName(_queries
.get(queryId).getKey(i))) + "\"");
fw.write(" scale=\""
+ fieldTypes.getScale(normalizeFieldName(_queries
.get(queryId).getKey(i))) + "\"");
fw.write(" />\n");
}
fw.write(indent(-1) + normalizeTagName("</key_fields>") + "\n");
// Felder
fw.write(indent(1) + normalizeTagName("<fields>") + "\n");
Object[] fields = _queries.get(queryId).getFieldsKeys().keySet().toArray();
for (int i = 0; i < fields.length; i++) {
fw.write(indent() + "<" + normalizeTagName("field name=\"")
+ normalizeFieldName((String) fields[i]) + "\"");
fw.write(" type=\"" + fieldTypes.getTypeName(normalizeFieldName((String) fields[i])) + "\"");
fw.write(" typeID=\""+ fieldTypes.getTypeId(normalizeFieldName((String) fields[i]))+ "\"");
fw.write(" len=\""+ fieldTypes.getLength(normalizeFieldName((String) fields[i]))+ "\"");
fw.write(" scale=\""+ fieldTypes.getScale(normalizeFieldName((String) fields[i]))+ "\"");
fw.write(" />\n");
}
fields = null;
fw.write(indent(-1) + normalizeTagName("</fields>") + "\n");
fw.write(indent(-1) + "</"+ normalizeTagName(_xmlTagname + "_meta") + ">\n");
//// META END ////
// Records schreiben
fw.write(indent(1) + "<"
+ normalizeTagName(_xmlTagname + "_data") + ">\n");
// Zeilen
HashMap record = _queries.get(queryId).getFieldsKeys();
if (_log != null) {
_log.debug9("get: " + _queries.get(queryId).getTag()
+ " query_id=" + queryId);
}
fw.write(indent(1) + "<"
+ normalizeTagName(_xmlTagname + "_record name=\"")
+ _queries.get(queryId).getTag() + "\">\n");
fw
.write(indent(1) +
"<" + normalizeTagName(_xmlTagname + "_fields") +
(_queries.get(queryId).getOperation() != null && _queries.get(queryId).getOperation().length() > 0
? " operation=\"" + _queries.get(queryId).getOperation() + "\" "
: "") +
">\n");
for (Iterator it = record.keySet().iterator(); it.hasNext();) {
String key = it.next().toString();
if (record.get(key) != null) {
switch (fieldTypes
.getTypeId(normalizeFieldName(key))) {
case Types.DATE:
case Types.TIMESTAMP:
String val = record.get(key).toString();
if (val.endsWith(".0")) {
record.put(key, val.substring(0, val
.length() - 2));
}
}
}
if(record.get(key) != null && record.get(key).toString().length() > 0) {
fw.write(indent() + "<" + normalizeTagName(key)
+ " null=");
if (record.get(key) != null)
fw.write("\"false\"><![CDATA["
+ asXml(record.get(key).toString())
+ "]]>");
else
fw.write("\"true\"><![CDATA[]]>");
fw.write("</" + normalizeTagName(key) + ">\n");
}
} // iteration Fields
fw.write(indent(-1) + "</"+ normalizeTagName(_xmlTagname + "_fields")+ ">\n");
// Rekursion independend refs
if (_queries.get(queryId).getIndepdRefCnt() > 0) {
for (int j = 0; j < _queries.get(queryId)
.getIndepdRefCnt(); j++) {
int recQuery = _queries.get(queryId)
.getIndepdRef(j).intValue();
if (_log != null)
_log
.debug6("recursive independend query: "
+ _queries.get(recQuery)
.getQuery());
exportQueries(recQuery, queryParams(recQuery,
record), fw);
}
}
// Rekursion dependend refs
if (_queries.get(queryId).getDependRefCnt() > 0) {
for (int j = 0; j < _queries.get(queryId)
.getDependRefCnt(); j++) {
int recQuery = _queries.get(queryId)
.getDependRef(j).intValue();
if (_log != null)
_log
.debug6("recursive dependend query: "
+ _queries.get(recQuery)
.getQuery());
exportQueriesForDelete(recQuery, queryParams(recQuery,
record), fw);
}
}
fw
.write(indent(-1) + "</"
+ normalizeTagName(_xmlTagname + "_record")
+ ">\n");
fw.write(indent(-1) + "</"
+ normalizeTagName(_xmlTagname + "_data") + ">\n");
fw.write(indent(-1) + "</"
+ normalizeTagName(_xmlTagname + "_package") + ">\n");
_queries.get(queryId).setDone(true);
return "";
} catch (Exception e) {
throw new Exception("SOSExport.exportQueries: " + e.getMessage(), e);
}
}
/**
* Rekursiver Export einer Abfrage mit deren Unterabfragen.
*
* @param queryId
* Nr. der aktuellen Abfrage
* @param parameterValues
* Substitutionswerte für den SQL-Statement
* @return XML Export als String
* @throws java.lang.Exception
*/
private String exportQueries(int queryId, ArrayList parameterValues)
throws Exception {
StringBuffer output = new StringBuffer();
try {
if (_log != null)
_log.debug3("export_queries: name=\""
+ _queries.get(queryId).getTag() + "\" query_id=\""
+ queryId + "\" key=\""
+ _queries.get(queryId).keysToStr()
+ "\" dependend=\""
+ _queries.get(queryId).dependRefToStr()
+ "\" independend=\""
+ _queries.get(queryId).indepdRefToStr() + "\"");
_rekursionCnt++;
// Parameterwerte in das SQL-Statement einfuegen
String queryStm = substituteQuery(_queries.get(queryId).getQuery(),
parameterValues);
HashMap allFieldNames = prepareGetFieldName(queryStm);
// Feldinformationen abrufen
SOSImExportTableFieldTypes fieldTypes = getFieldTypes(queryStm
.toString());
// Daten abrufen
ArrayList result = new ArrayList();
result = getArray(queryStm.toString());
output.append(indent(1) + "<"
+ normalizeTagName(_xmlTagname + "_package id=\"")
+ _queries.get(queryId).getTag() + "\">\n");
if (!result.isEmpty()) {
//// META START ////
output.append(indent(1) + "<"
+ normalizeTagName(_xmlTagname + "_meta") + ">\n");
output.append(indent(0) + "<"
+ normalizeTagName("table name=\"")
+ _queries.get(queryId).getTag() + "\" />\n");
// Key-Felder
output.append(indent(1) + "<" + normalizeTagName("key_fields")
+ ">\n");
for (int i = 0; i < _queries.get(queryId).getKeyCnt(); i++) {
if (_log != null)
_log.debug6("key_field[" + i + "]=\""
+ _queries.get(queryId).getKey(i) + "\"");
output.append(indent()
+ "<"
+ normalizeTagName("field name=\"")
+ normalizeFieldName(_queries.get(queryId)
.getKey(i)) + "\"");
output.append(" type=\""
+ fieldTypes
.getTypeName(normalizeFieldName(_queries
.get(queryId).getKey(i))) + "\"");
output.append(" typeID=\""
+ fieldTypes.getTypeId(normalizeFieldName(_queries
.get(queryId).getKey(i))) + "\"");
output.append(" len=\""
+ fieldTypes.getLength(normalizeFieldName(_queries
.get(queryId).getKey(i))) + "\"");
output.append(" scale=\""
+ fieldTypes.getScale(normalizeFieldName(_queries
.get(queryId).getKey(i))) + "\"");
output.append(" />\n");
}
output.append(indent(-1) + normalizeTagName("</key_fields>")
+ "\n");
// Felder
output.append(indent(1) + normalizeTagName("<fields>") + "\n");
Object[] fields = ((HashMap) result.get(0)).keySet().toArray();
for (int i = 0; i < fields.length; i++) {
output.append(indent() + "<"
+ normalizeTagName("field name=\"")
+ normalizeFieldName((String) fields[i]) + "\"");
output
.append(" type=\""
+ fieldTypes
.getTypeName(normalizeFieldName((String) fields[i]))
+ "\"");
output
.append(" typeID=\""
+ fieldTypes
.getTypeId(normalizeFieldName((String) fields[i]))
+ "\"");
output
.append(" len=\""
+ fieldTypes
.getLength(normalizeFieldName((String) fields[i]))
+ "\"");
output
.append(" scale=\""
+ fieldTypes
.getScale(normalizeFieldName((String) fields[i]))
+ "\"");
output.append(" />\n");
}
fields = null;
output
.append(indent(-1) + normalizeTagName("</fields>")
+ "\n");
output.append(indent(-1) + "</"
+ normalizeTagName(_xmlTagname + "_meta") + ">\n");
//// META END ////
// Records schreiben
output.append(indent(1) + "<"
+ normalizeTagName(_xmlTagname + "_data") + ">\n");
// Zeilen
for (int i = 0; i < result.size(); i++) {
HashMap record = (HashMap) result.get(i);
if (_log != null)
_log.debug9("get: "
+ _queries.get(queryId).getTag()
+ " query_id=" + queryId);
output.append(indent(1) + "<"
+ normalizeTagName(_xmlTagname + "_record name=\"")
+ _queries.get(queryId).getTag() + "\">\n");
output
.append(indent(1) + "<"
+ normalizeTagName(_xmlTagname + "_fields")
+ ">\n");
// Spalten alphabetische Sortierung
//Vector record_vector = new Vector(record.keySet());
//Collections.sort(record_vector);
//for (Iterator it = record_vector.iterator();
// it.hasNext(); ) {
for (Iterator it = record.keySet().iterator(); it.hasNext();) {
String key = it.next().toString();
String lobType = null;
switch (fieldTypes.getTypeId(normalizeFieldName(key))) {
case Types.LONGVARCHAR:
lobType = "clob";
case Types.BINARY:
if (lobType == null) lobType = "blob";
case Types.BLOB:
if (lobType == null) lobType = "blob";
case Types.CLOB:
if (lobType == null) lobType = "clob";
case Types.LONGVARBINARY:
if (lobType == null) lobType = "blob";
case Types.VARBINARY:
if (lobType == null) lobType = "blob";
//// als binaer behandeln und in hex umwandeln ////
// create blob-stm
int posBegin = new String(queryStm).toLowerCase()
.indexOf("from");
int posEnd = new String(queryStm).toLowerCase()
.indexOf(" ", posBegin + 5);
StringBuffer queryBlobStm = new StringBuffer();
String blobFieldName = getBlobFieldName(allFieldNames, key
.toString());
queryBlobStm.append("SELECT "
+ normalizeFieldName(blobFieldName) + " ");
if (posEnd < posBegin) posEnd = queryStm.length();
queryBlobStm.append(queryStm.substring(posBegin,
posEnd));
String and = " WHERE ";
for (int j = 0; j < _queries.get(queryId)
.getKeyCnt(); j++) {
//queryBlobStm.append(and + "\""+
// normalizeFieldName(_queries.get(queryId).getKey(j))
// + "\"=");
String keyFieldName = getKeyFieldName(allFieldNames,
_queries.get(queryId).getKey(j));
queryBlobStm.append(and
+ normalizeFieldName(keyFieldName)
+ " =");
queryBlobStm
.append(quote(
fieldTypes
.getTypeId(normalizeFieldName(_queries
.get(queryId)
.getKey(j))),
(String) record
.get(normalizeFieldName(_queries
.get(queryId)
.getKey(j)))));
and = " AND ";
}
// blob mit Umbruch ausgeben
byte[] blob = null;
if (lobType.equals("blob")) {
blob = _conn.getBlob(queryBlobStm.toString());
} else {
blob = str2bin(_conn.getClob(queryBlobStm
.toString()));
}
output.append(indent() + "<"
+ normalizeTagName(key) + " null=");
if (blob != null && blob.length > 0) {
indent(1);
output
.append("\"false\">\n"
+ toHexString(blob, indent(),
_lineWrap) + "\n"
+ indent(-1));
} else {
output.append("\"true\">");
}
output.append("</" + normalizeTagName(key) + ">\n");
break;
// ...sonst als xml string ausgeben
default:
// TODO Workaround - Millisekunden entfernen
if (record.get(key) != null) {
switch (fieldTypes
.getTypeId(normalizeFieldName(key))) {
case Types.DATE:
case Types.TIMESTAMP:
String val = record.get(key).toString();
if (val.endsWith(".0")) {
record.put(key, val.substring(0, val
.length() - 2));
}
}
}
output.append(indent() + "<"
+ normalizeTagName(key) + " null=");
if (record.get(key) != null)
output.append("\"false\"><![CDATA["
+ asXml(record.get(key).toString())
+ "]]>");
else
output.append("\"true\"><![CDATA[]]>");
output.append("</" + normalizeTagName(key) + ">\n");
} // switch
} // iteration Fields
output
.append(indent(-1) + "</"
+ normalizeTagName(_xmlTagname + "_fields")
+ ">\n");
// Rekursion independend refs
if (_queries.get(queryId).getIndepdRefCnt() > 0) {
for (int j = 0; j < _queries.get(queryId)
.getIndepdRefCnt(); j++) {
int recQuery = _queries.get(queryId)
.getIndepdRef(j).intValue();
if (_log != null)
_log
.debug6("recursive independend query: "
+ _queries.get(recQuery)
.getQuery());
output.append(exportQueries(recQuery, queryParams(
recQuery, record)));
}
}
// Rekursion dependend refs
if (_queries.get(queryId).getDependRefCnt() > 0) {
for (int j = 0; j < _queries.get(queryId)
.getDependRefCnt(); j++) {
int recQuery = _queries.get(queryId)
.getDependRef(j).intValue();
if (_log != null)
_log
.debug6("recursive dependend query: "
+ _queries.get(recQuery)
.getQuery());
output.append(exportQueries(recQuery, queryParams(
recQuery, record)));
}
}
output
.append(indent(-1) + "</"
+ normalizeTagName(_xmlTagname + "_record")
+ ">\n");
} // iteration Records
output.append(indent(-1) + "</"
+ normalizeTagName(_xmlTagname + "_data") + ">\n");
} // if results
output.append(indent(-1) + "</"
+ normalizeTagName(_xmlTagname + "_package") + ">\n");
_queries.get(queryId).setDone(true);
//System.out.println("output : " + output.toString());
//_log.debug9("output : "+output.toString());
return output.toString();
} catch (Exception e) {
throw new Exception("SOSExport.exportQueries: " + e.getMessage(), e);
}
}
/***************************************************************************
* Da es im SQL Statement Felder mit "AS" selektiert werden k�nnen, ordnet
* diese Methode die originale Feldnamen zu dem neuen Feldnamen zu z.B :
* select vorname as name,nachname from table [name] = vorname [nachname] =
* nachname
*
* @param stmt
* SQL Statement
* @return wenn select * leere HashMap, sonst HashMap mit dem Schl�ssel
* -neuer Feldname wert - alter Feldname
**************************************************************************/
private HashMap prepareGetFieldName(String stmt) throws Exception {
int posBegin = new String(stmt).toUpperCase().indexOf("SELECT");
int posEnd = new String(stmt).toUpperCase().indexOf("FROM");
if (posBegin == -1 || posEnd == -1) { throw new Exception(
"sql statement is not valid : " + stmt); }
String selectFields = stmt.substring(posBegin + 6, posEnd).trim()
.toUpperCase();
HashMap hm = new HashMap();
if (!selectFields.equals("*")) {
String[] splitFields = selectFields.split(",");
for (int i = 0; i < splitFields.length; i++) {
String field = splitFields[i].trim();
String[] split = field.split(" ");
int len = split.length;
if (len > 1) {
String lastName = split[len - 1].replace('"', ' ').trim();
if (field.indexOf(" AS ") != -1) {
String firstName = split[0].replace('"', ' ').trim();
hm.put(lastName, firstName);
}
} else {
String firstName = field.replace('"', ' ').trim();
hm.put(firstName, firstName);
}
}
}
return hm;
}
/**
* da es vorkommen kann, dass mann einen Blob|Clob unter einem anderen Namen
* selektiert, (select BLOB_FELD as BLOB ...) ermittelt diese Methode
* Blob|Clob Feldname f�r getBlob
*
* @param stmt
* gesamte SQL Statement
* @param sampleFieldName
* Feldname aus DB Meta-Daten
*
*/
private String getBlobFieldName(HashMap hm, String sampleFieldName)
throws Exception {
String sample = sampleFieldName.toUpperCase();
if (hm != null && hm.size() > 0) {
if (hm.containsKey(sample)) { return "\"" + hm.get(sample)
+ "\" as \"" + sample + "\""; }
}
return "\"" + sample + "\"";
}
/**
* @param stmt
* gesamte SQL Statement
* @param sampleFieldName
* Feldname aus DB Meta-Daten
*
*/
private String getKeyFieldName(HashMap hm, String sampleFieldName)
throws Exception {
String sample = sampleFieldName.toUpperCase();
if (hm != null && hm.size() > 0) {
if (hm.containsKey(sample)) { return "\"" + hm.get(sample) + "\""; }
}
return "\"" + sample + "\"";
}
/**
* Liefert die Abfrageparameter als kommaseparierte Liste.
*
* @param queryId
* Nr. der Abfrage
* @param record
* HashMap mit Record-Daten
* @return kommaseparierte Liste der Parameter
* @throws java.lang.Exception
*/
public ArrayList queryParams(int queryId, HashMap record) throws Exception {
//private ArrayList queryParams(int queryId, HashMap record) throws Exception {
ArrayList values = new ArrayList();
try {
if (_log != null) _log.debug3("query_params: query_id=" + queryId);
for (int i = 0; i < _queries.get(queryId).getParameterCnt(); i++) {
if (_log != null)
_log.debug6("param_value[" + i + "] = "
+ _queries.get(queryId).getParameter(i));
if (record.containsKey(normalizeFieldName(_queries.get(queryId)
.getParameter(i))))
values.add(record.get(normalizeFieldName(_queries.get(
queryId).getParameter(i))));
}
return values;
} catch (Exception e) {
throw new Exception("SOSExport.queryParams: " + e.getMessage(), e);
}
}
/**
* F?gt die Parameterwerte der Reihe nach in das SQL-Statement ein.
*
* @param query
* SQL-Statement, in dem jedes ?-Zeichen substituiert wird
* @param values
* Werte, die mit den ?-Zeichen substituiert werden sollen
* @return substituiertes SQL-Statement
*/
private String substituteQuery(String query, ArrayList values) {
int matches = countStr(query, "?");
String[] queryParts = query.split("\\?");
if (matches == 0) return query;
// zu wenige werte
if (matches > values.size())
throw new IllegalArgumentException(
"SOSExport.substituteQuery: too few values for substitution");
StringBuffer queryStm = new StringBuffer();
for (int i = 0; i < queryParts.length; i++) {
queryStm.append(queryParts[i]);
if (i < values.size()) {
if (values.get(i) == null || values.get(i).equals(""))
queryStm.append("NULL");
else
queryStm.append(values.get(i));
}
}
return queryStm.toString();
}
/**
* Liefert die Anzahl der Vorkommen von part in string.
*
* @param string
* String, in dem gesucht werden soll
* @param part
* Teilstring, der gesucht werden soll
* @return gefundene Anzahl von part in string
*/
private static int countStr(String string, String part) {
int index = 0;
int matches = 0;
index = string.indexOf(part, index);
while (index >= 0) {
matches++;
index = string.indexOf(part, ++index);
}
return matches;
}
/**
* Liefert die Treffer als ArrayList aus HashMaps zurück. Die Feldnamen
* sind in lower-case abgespeichert. SQL NULL Werte und Blobs/Clobs werden
* mit null abgelegt.
*
* @param query
* SQL-Statement
* @return ArrayList aus HashMaps
* @throws Exception
*/
private ArrayList getArray(String query) throws Exception {
try {
_conn.executeQuery(query);
ResultSet rs = _conn.getResultSet();
java.sql.ResultSetMetaData rsmd = rs.getMetaData();
int i, n = rsmd.getColumnCount();
ArrayList result = new ArrayList();
while (rs.next()) {
HashMap row = new HashMap(n);
for (i = 1; i <= n; i++) {
switch (rsmd.getColumnType(i)) {
case Types.BIGINT:
case Types.DECIMAL:
case Types.DOUBLE:
case Types.FLOAT:
case Types.INTEGER:
case Types.REAL:
case Types.SMALLINT:
case Types.NUMERIC:
case Types.TINYINT:
case Types.DATE:
case Types.TIMESTAMP:
row.put(rsmd.getColumnName(i), rs.getString(i));
break;
case Types.LONGVARCHAR:
case Types.BINARY:
case Types.BLOB:
case Types.CLOB:
case Types.LONGVARBINARY:
case Types.VARBINARY:
row.put(rsmd.getColumnName(i), null);
default:
row.put(rsmd.getColumnName(i), rs.getString(i));
}
}
result.add(row);
}
rs.close();
return result;
} catch (Exception e) {
throw new Exception("SOSExport.getArray: " + e.getMessage());
}
}
/**
* Liefert die Feldbeschreibungen zu einem SQL-Statement. Es wird in das
* SQL-Statement entsprechend ein 1=0 eingefügt.
*
* @param query
* SQL-Statement, aus dem die Feldinformationene gewonnen werden
* sollen
* @return Eine Liste der gefundenen Felbeschreibungen
* @throws Exception
*/
private SOSImExportTableFieldTypes getFieldTypes(String query)
throws Exception {
try {
// 1=0 unter beruecksichtigung von einem order by am ende
// hinzufuegen
StringBuffer stm = new StringBuffer();
int index = query.toLowerCase().indexOf("order by");
if (index >= 0)
stm.append(query.substring(0, index - 1));
else
stm.append(query);
if (query.toLowerCase().indexOf("where") >= 0)
stm.append(" AND 1=0");
else
stm.append(" WHERE 1=0");
if (index >= 0) stm.append(query.substring(index - 1));
// Feldinformationen abrufen
_conn.executeQuery(stm.toString());
ResultSet resultSet = _conn.getResultSet();
SOSImExportTableFieldTypes fieldTypes = new SOSImExportTableFieldTypes();
HashMap fieldDesc = new HashMap();
for (int i = 1; i <= resultSet.getMetaData().getColumnCount(); i++) {
fieldDesc = _conn.fieldDesc(i);
Integer type = new Integer(fieldDesc.get("columnType")
.toString());
BigInteger size = new BigInteger(fieldDesc.get(
"columnDisplaySize").toString());
Integer scale = new Integer(fieldDesc.get("scale").toString());
if (_log != null)
_log.debug9("field_type: name="
+ fieldDesc.get("columnName") + " type="
+ fieldDesc.get("columnTypeName") + " type_id="
+ type + " size=" + size + " scale=" + scale);
fieldTypes
.addField(
normalizeFieldName(normalizeFieldName((String) fieldDesc
.get("columnName"))),
(String) fieldDesc.get("columnTypeName"), type,
size, scale);
}
resultSet.close();
return fieldTypes;
} catch (Exception e) {
throw new Exception("SOSExport.getFieldTypes: " + e.getMessage(), e);
}
}
/**
* Quotiert einen Wert anhand seines SQL-Typs.
*
* @param type
* jdbc Typ-ID des Feldes
* @param val
* zu quotierender Wert
* @return Quotierter Wert
*/
private String quote(int type, String val) {
if (val == null)
return "NULL";
else if (val.equals("")) return "NULL";
switch (type) {
case Types.DOUBLE:
if (val.equalsIgnoreCase("null")) val = "NULL";
/*
* String[] vals = val.split("\\."); if(vals.length > 1) return
* vals[0];
*/
return val;
case Types.BIGINT:
case Types.DECIMAL:
case Types.FLOAT:
case Types.INTEGER:
case Types.REAL:
case Types.SMALLINT:
case Types.NUMERIC:
case Types.TINYINT:
if (val.equalsIgnoreCase("null")) val = "NULL";
return val;
case Types.DATE:
case Types.TIMESTAMP:
return "%timestamp_iso('" + val + "')";
default:
val = val.replaceAll("'", "''");
if (_conn instanceof SOSMySQLConnection) // nur bei MySQL
val = val.replaceAll("\\\\", "\\\\\\\\"); // einfache durch
// doppelte
return "'" + val + "'";
}
}
/**
* Gibt die kleinere zweier Zahlen zurück.
*
* @param eins
* Erste Zahl
* @param zwei
* Zweite Zahl
* @return die kleinere Zahl
*/
private int min(int eins, int zwei) {
if (eins < zwei)
return eins;
else
return zwei;
}
/**
* Liefert einen String für die Einrückung zurück. Ein pos.
* Wert erhöht die Einrückungsstufe für den nächste
* Aufruf und ein neg. veringert diese um den Wert.
*
* @param indent
* relative Einrückungsstufe
* @return fertiger String für die Einrückung
*/
private String indent(int indent) {
int curIndent = _xmlIndent;
_xmlIndent += indent;
StringBuffer output = new StringBuffer(curIndent);
if (indent > 0)
for (int i = 0; i < curIndent; i++)
output.append(_xmlIndentation);
else
for (int i = 0; i < _xmlIndent; i++)
output.append(_xmlIndentation);
return output.toString();
}
/**
* Liefert einen String für die Einrückung zurück -
* gleichbleibend.
*
* @return fertiger String für die Einrückung
*/
private String indent() {
return indent(0);
}
/**
* Normalisiert anhand von _normalizeTagName einen Tag.
*
* @param tag
* String des Tags
* @return normalisierter String des Tags
*/
private String normalizeTagName(String tag) {
if (_normalizeTagName.equalsIgnoreCase("strtoupper"))
return tag.toUpperCase();
else
return tag.toLowerCase();
}
/**
* Normalisiert anhand von _normalizeFieldName einen Feldnamen.
*
* @param field
* String des Feldnamen
* @return normalisierter String des Feldnamen
*/
private String normalizeFieldName(String field) {
if (_normalizeFieldName.equalsIgnoreCase("strtoupper"))
return field.toUpperCase();
else
return field.toLowerCase();
}
/**
* Wandelnt einen String in einen XML konformen String um.
*
* @param str
* Eingabestring
* @return XML konformer String
*/
private static String asXml(String str) {
//str.replaceAll("<", "<");
//str.replaceAll(">", ">");
//str.replaceAll("\n", " ");
//str.replaceAll("\r", " ");
//str.replaceAll(" ", " ");
return str;
}
/**
* Wandelt einen String in ein Byte-Array um.
*
* @param str
* String
* @return Byte-Array des Strings
*/
private static byte[] str2bin(String str) {
return str.getBytes();
}
/**
* Schreibt ein Byte-Array in eine Datei.
*
* @param bin
* Byte-Array
* @param indent
* Indent-String
* @param wrap
* Zeilenumbruch (0 = keiner)
* @return Hex-String des Byte-Arrays
*/
private static String toHexString(byte[] b, String indent, int wrap , Writer fw) throws Exception {
int length = b.length * 2;
int indentLength = indent.length();
if (wrap > 0) {
// Die Laenge mit Zeilenumbruch und Einrueckungen ermitteln
int indents = length / (wrap - indentLength);
length = length + indents * (indentLength + "\n".length());
length += indentLength; // erste Einrueckung
}
int line = indentLength;
if (wrap > 0){
fw.write(indent);
}
for (int i = 0; i < b.length; i++) {
// oberer Byteanteil
fw.write(_hexChar[(b[i] & 0xf0) >>> 4]);
// unterer Byteanteil
fw.write(_hexChar[b[i] & 0x0f]);
line += 2;
// Zeilenumbruch mit Einrueckung
if (wrap > 0 && line >= wrap && i < (b.length - 1)) {
fw.write("\n" + indent);
line = indentLength;
}
}
return "";
}
/**
* Wandelt ein Byte-Array in ein Hex-String um.
*
* @param bin
* Byte-Array
* @param indent
* Indent-String
* @param wrap
* Zeilenumbruch (0 = keiner)
* @return Hex-String des Byte-Arrays
*/
private static String toHexString(byte[] b, String indent, int wrap) {
int length = b.length * 2;
int indentLength = indent.length();
if (wrap > 0) {
// Die Laenge mit Zeilenumbruch und Einrueckungen ermitteln
int indents = length / (wrap - indentLength);
length = length + indents * (indentLength + "\n".length());
length += indentLength; // erste Einrueckung
}
int line = indentLength;
StringBuffer sb = new StringBuffer(length);
if (wrap > 0) sb.append(indent);
for (int i = 0; i < b.length; i++) {
// oberer Byteanteil
sb.append(_hexChar[(b[i] & 0xf0) >>> 4]);
// unterer Byteanteil
sb.append(_hexChar[b[i] & 0x0f]);
line += 2;
// Zeilenumbruch mit Einrueckung
if (wrap > 0 && line >= wrap && i < (b.length - 1)) {
sb.append("\n" + indent);
line = indentLength;
}
}
return sb.toString();
}
}