/*
 * Class responsible for db connection via servlet
 * originally inspired by
 // Beispielklasse aus dem JavaTutorial (http://java.sun.com/docs/books/tutorial)  * 
 *  @(#)JDBCAdapter.java	1.5 97/12/03
 *
 */

package de.superx.applet;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
import java.util.Vector;

import javax.swing.JOptionPane;

import de.memtext.baseobjects.User;
import de.memtext.rights.NewPasswordChecker;
import de.memtext.util.CryptUtils;
import de.memtext.util.DSAHandler;
import de.memtext.util.NumberUtils;
import de.memtext.util.StringUtils;
import de.memtext.widgets.WarningMessage;
import de.superx.common.SxResultRow;
import de.superx.common.SuperX_el;
import de.superx.common.SxResultSet;
import de.superx.common.TemplateProcessor;

/**
 * Ein Adapter, der das JDBC interface an das TableModelinterface anpasst.
 * Angepasst für SuperX
 * 
 */

public class SxSQL {
	// Connection connection;
	static URL superXDbServletUrl;
	static HttpURLConnection servletConnection; // Wint
	static private Integer userID = new Integer(-1);
	static DSAHandler dsaHandler;
	static boolean isClosed = true;
	static Statement statement = null;
	static ResultSet resultSet = null;
	static String aktuelleNachricht = null;
	// obsolete static fields, shouldn't be used,
	// because of cloning
	// static String[] columnNames = {};
	static int updateCount = -1;
	static int numberOfColumns = -1;
	static Class[] columnTpyes = {};
	static SxResultSet rows = new SxResultSet();
	static Vector rows_ret = new Vector();

	static SuperX_el gesamt = new SuperX_el();
	static SxSQLMetaData metaData;
	static private String logToKonsole = "";
	static StringBuffer prot_sql = new StringBuffer();
	static InetAddress client_addr = null;
	static String client_ip = null;
	static InetAddress client_dns = null;
	static int proto_fkt_id = 2; // LOGIN_FAIL
	static int proto_id_pos = -1;
	static int user_id_pos = -1;
	static String errorString = null;
	static Short adminUserInt = new Short((short) 0);
	static String sx_db = (String) SxDefaults.getPropertyValue("SxDB");
	static ObjectInputStream inputFromServlet = null;
	static ObjectOutputStream outputToServlet = null;
	static TemplateProcessor templateProcessor = new TemplateProcessor();
	// wird von SxDefaults.init gesetzt
	static String mandantenID = "default";
	static String jsessionid;
	static NewPasswordChecker newPasswordChecker;

	// static String originalUrl;
	// static String url;
	private SxSQL() {
	}

	/**
	 * 
	 * @param user
	 * @throws Exception
	 */
	static void check(User user) throws Exception {

		initProtokolEntry();
		try {

			isClosed = false;

			// throws exeception if something is/goes wrong
			checkPwd(user);

			// Protokollierung macht UserInializer im servlet
			proto_fkt_id = 1; // LOGIN
			prot_sql.replace(proto_id_pos, proto_id_pos + 1, (new Integer(
					proto_fkt_id)).toString());

			// execute(prot_sql.toString());
			isClosed = false;
		} catch (Exception ex) {
			String msg = ex.toString();

			user_id_pos = prot_sql.toString().indexOf("%");
			if (user_id_pos > 0)
				prot_sql.replace(user_id_pos, user_id_pos + 1, "-1");
			// if (!isClosed) execute(prot_sql.toString());
			throw new SQLException(msg);
		}
	}

	/**
	 * @deprecated macht der UserInitializer im Servlet
	 * @throws UnknownHostException
	 */
	static private void initProtokolEntry() throws UnknownHostException {
		client_addr = InetAddress.getLocalHost();
		client_ip = client_addr.getHostAddress();
		client_dns = InetAddress.getByName(client_ip);

		// System.out.println("adrr:" + client_addr + " ip: " + client_ip + "
		// client_name: " + client_dns.getHostName());
		prot_sql.append("insert into protokoll (proto_fkt_id, userinfo_id, ");
		prot_sql.append("ip_adresse, client_name, zeitpunkt) values (");
		prot_sql.append("?, ");
		prot_sql.append("% , '" + client_ip);
		prot_sql.append("', '" + client_dns.getHostName() + "'");
		if (sx_db.equals("Postgres")) {
			prot_sql.append(", now());");
		} else {
			prot_sql.append(", current);");
		}

		// , date('"+SxDate.getNowString()+"'));");

		proto_id_pos = prot_sql.toString().indexOf("?");
		prot_sql.replace(proto_id_pos, proto_id_pos + 1, (new Integer(
				proto_fkt_id)).toString());
	}

	static void readFMTemplates() throws SQLException {
		// Spezielles Kommando, dass das SuperXDBServlet versteht und
		// die templates im SuperX_el Objekt zurückschickt
		executeQuery("readFMBasics");
		if (gesamt.getRawFmTemplates() == null)
			throw new SQLException(
					"Servlet hat keine FreeMarker Templates geschickt");
		templateProcessor.setTemplates(gesamt.getRawFmTemplates());
		if (gesamt.getRepository() == null)
			throw new SQLException(
					"Servlet hat keine Sx_Repository Daten geschickt");

		templateProcessor.setRepositoryMap(gesamt.getRepository());
		// damit nicht immer hin-und her geschickt werden muss
		gesamt.setRepository(null);
	}

	/**
	 * checkPwd initialisiert User setzt id des Users wird auch von
	 * SxPasswdChangeDlg aufgerufen
	 * 
	 * @param user
	 * @throws Exception
	 */
	static synchronized void checkPwd(User user) throws Exception {

		boolean login_ok = false;
		try {
			String auth_sql = "Anmeldung|" + user.getName() + "|"
					+ user.getPasswd();
			// der select auf userinfo wird automatisch im Servlet generiert
			/*
			 * "|select tid, passwd_sha, administration,akt_versuch,max_versuch"
			 * + " from userinfo where benutzer = '" + user.getName() + "';";
			 */

			executeQuery(auth_sql);

			if (getRowCount() == 0) {
				throw new Exception("Die Anmeldung des Users '"
						+ user.getName() + "' war nicht erfolgreich");
			}
			SxResultRow V_row = (SxResultRow) rows.first();

			Short aktVersuch;
			Short maxVersuch;
			try {
				// normal Informix
				aktVersuch = (Short) V_row.get(3);
			} catch (ClassCastException e) {
				// Access / Postgres liefern Integer-Wrapper
				Integer dummy = (Integer) V_row.get(3);
				Short dummy2 = new Short((short) dummy.shortValue());
				aktVersuch = dummy2;
			}
			try {
				// normal Informix
				maxVersuch = (Short) V_row.get(4);
			} catch (ClassCastException e) {
				// Access / Postgres liefern Integer-Wrapper
				Integer dummy = (Integer) V_row.get(4);
				Short dummy2 = new Short((short) dummy.shortValue());
				maxVersuch = dummy2;
			}

			// Short aktVersuch = (Short) V_row.get(3);
			// Short maxVersuch = (Short) V_row.get(4);
			if (aktVersuch.shortValue() > maxVersuch.shortValue()
					|| aktVersuch.shortValue() <= (maxVersuch.shortValue() * -1)) {
				throw new Exception(
						"Die Zahl maximaler Login-Versuche für Benutzer '"
								+ user.getName() + "' ist überschritten.");
			}

			userID = (Integer) V_row.get(0);
			user.setId(userID);
			try {
				// normal Informix
				adminUserInt = (Short) V_row.get(2);
			} catch (ClassCastException e) {
				// Access / Postgres liefern Integer-Wrapper
				Integer dummy = (Integer) V_row.get(2);
				Short dummy2 = new Short((short) dummy.shortValue());
				adminUserInt = dummy2;
			}
			user.setAdmin(isAdmin());

			user_id_pos = prot_sql.toString().indexOf("%");
			if (user_id_pos > 0)
				prot_sql.replace(user_id_pos, user_id_pos + 1,
						userID.toString());
			String passwd_sha = (String) V_row.get(1);
			Object kennwortSpalte = V_row.get(5);

			/*
			 * executeQuery("select pw_gueltig_bis from user_pw where userinfo_id="
			 * +userID); if (rows.size()>0) { Vector zeile= (Vector)
			 * rows.get(0); java.util.Date datum=(java.util.Date)zeile.get(0);
			 * if (datum!=null&&!DateUtils.isDateInFuture(datum))
			 * kennwortSpalte="ändern"; }
			 */
			if (kennwortSpalte != null
					&& kennwortSpalte.toString().trim().equals("ändern")) {
				try {
					login_ok = changePwd(user);
				} catch (Exception e) {
					String msg = e.toString();
					msg = msg.substring(msg.lastIndexOf(":") + 1);
					e.printStackTrace();

					JOptionPane.showMessageDialog(null, msg, "Fehler",
							JOptionPane.ERROR_MESSAGE);
					login_ok = false;
					throw new RuntimeException("Fehler bei Passwortänderung:"
							+ e);
				}

			}
			// DQ 6.10.2006 erstmal ins SuperxDBServlet (Methode doPost)
			// verlagert
			/*
			 * if (passwd_sha.equals(CryptUtils.encodeSHA(user.getPasswd()))) {
			 * if (aktVersuch.shortValue() >= 0) { login_ok = true; } else {
			 * login_ok = true; login_ok = changePwd(user); } }
			 */
			login_ok = true;

			if (login_ok) {
				SxSQL.initParams();
				// execute("update userinfo set akt_versuch=0 where benutzer =
				// '" + user.getName() + "'");
			} else {
				String operator = "+";
				if (aktVersuch.shortValue() < 0)
					operator = "-";
				/*
				 * String sql = "update userinfo set akt_versuch=akt_versuch" +
				 * operator + "1 " + " where benutzer = '" + user.getName() +
				 * "';"; execute(sql);
				 */
				throw new Exception("Fehlerhaftes Kennwort für Benutzer '"
						+ user.getName() + "'");

			}
		} catch (SQLException e) {
			e.printStackTrace();
			String msg = "Datenbankverbindung konnte nicht aufgebaut werden. "
					+ e.toString();
			msg = msg.replace(':', '-');
			if (msg.indexOf("NichtAngemeldetException") > -1)
				throw new IllegalStateException(
						"Anmeldung fehlerhaft oder abgelaufen");
			else
				throw new Exception(msg);
		}
	}

	/**
	 * @deprecated sollte das XMl-Frontend machen
	 * @param user
	 * @return
	 * @throws Exception
	 */
	private static boolean changePwd(User user) throws Exception {
		boolean login_ok;
		SxPasswdChangeDlg dlg = new SxPasswdChangeDlg(null,
				"Bitte ändern Sie Ihr Passwort ");
		dlg.setUsername(user.getName());
		dlg.setNewPasswordChecker(SxSQL.newPasswordChecker);
		dlg.setOldPassword(user.getPasswd());
		dlg.setUsernameFieldEnabled(false);
		dlg.setCheckOldPasswdWanted(false);
		dlg.show();
		if (dlg.wasOkSelected()) {
			storePwd(user, dlg.getNewPasswd(), false);
			login_ok = true;
			execute("update userinfo set kennwort=null where tid=" + userID);
		} else {
			login_ok = false;
			WarningMessage
					.show(null,
							"Sie können mit SuperX nur arbeiten,wenn Sie Ihr Passwort ändern.\nBitte melden Sie dazu sich neu an.",
							"SuperX");
			throw new RuntimeException("Passwortänderung nötig");
		}
		return login_ok;
	}

	static public Integer getUserID() {
		// kopieren damit keiner von außen aus Versehen überschreibt
		if (userID != null)
			return new Integer(userID.intValue());
		else {
			System.out
					.println("Achtung! userID dürfte eigentlich nicht null sein!!");
			return new Integer(-1);
		}
	}

	static public final synchronized void storePwd(User user, String newpasswd,
			boolean isCheckOldPasswdWanted) throws Exception {

		if (isCheckOldPasswdWanted && !isAdmin())
			checkPwd(user);

		execute("userchange|" + NumberUtils.getRandomInt(9)
				+ CryptUtils.encodeSHA(newpasswd + CryptUtils.geheimnis1) + "|"
				+ user.getName());

		if (gesamt.getUpdateCount() != 1)
			throw new Exception("Benutzer '" + user.getName() + "'"
					+ " nicht gefunden !");

		user.setPasswd(newpasswd);
		proto_fkt_id = 6; // CH_PASSWD_NEW
		// prot_sql.replace(proto_id_pos, proto_id_pos + 1, (new Integer(
		// proto_fkt_id)).toString());

		// execute(prot_sql.toString());
		// damit sichergestellt wird, das kein erneues Ändern nötig

		execute("update userinfo set akt_versuch=0 where benutzer = '"
				+ user.getName() + "'");
	}

	static public boolean isAdmin() {
		if (adminUserInt.intValue() > 0)
			return true;
		else
			return false;
	}

	public static synchronized void executeAll(String stmt) throws SQLException {

		// String bleibt zusammen, aber Schleife wird durchlaufen, um
		// Multi-Statement zu kennzeichnen

		StringTokenizer st = new StringTokenizer(stmt, ";");
		int n = 0;
		while (st.hasMoreTokens()) {
			n++;
			String sqlstmt = st.nextToken().trim();
			if (sqlstmt.length() < 10)
				break;
			// besser über String suchen!!
		}
		// execute (sqlstmt); Wint neu++
		if (n < 2) {
			executeQuery(stmt);
		} else {

			executeQuery("multi:" + stmt);
		}
	}

	static private synchronized void execute(String stmt) throws SQLException {

		applet_servlet_connection("single" + stmt);
	}

	static synchronized void executeQuery(String query) throws SQLException {
		if (!query.trim().equals("") && !query.trim().equals("null"))
			applet_servlet_connection(query);
	}

	static public int getUpdateCount() throws SQLException {
		return updateCount;
	}

	static public String getAktuelleNachricht() {
		return aktuelleNachricht;
	}

	static public int getColumnCount() {
		return numberOfColumns;
	}

	/*
	 * static public String getColumnName(int column) { if (columnNames[column]
	 * != null) return columnNames[column]; else return ""; }
	 */
	static public int getRowCount() {
		return rows.size();
	}

	/**
	 * static public Object getObjectAt(int aRow, int aColumn) { ResultRow row =
	 * (ResultRow) rows.get(aRow); return row.get(aColumn); }
	 */

	static public Vector getResultVector() {
		Vector v = new Vector();
		for (Iterator it = rows.iterator(); it.hasNext();) {
			SxResultRow r = (SxResultRow) it.next();
			Vector row = new Vector();
			for (Iterator it2 = r.iterator(); it2.hasNext();)
				row.add(it2.next());
			v.add(row);
		}
		return v;
	}

	static public SxResultSet getResult() {
		return rows;
	}

	static public SxSQLMetaData getResultSetMetaData() {
		/*
		 * try { FileOutputStream ostream = new FileOutputStream("t.tmp");
		 * ObjectOutputStream p_out = new ObjectOutputStream(ostream);
		 * 
		 * p_out.writeObject(metaData);
		 * 
		 * p_out.flush(); ostream.close(); } catch (Exception ex) {
		 * System.err.println (ex); }
		 */
		SxSQLMetaData meta = null;
		/*
		 * try { FileInputStream istream = new FileInputStream("t.tmp");
		 * ObjectInputStream p_in = new ObjectInputStream(istream);
		 * 
		 * meta = (SxSQLMetaData) p_in.readObject();
		 * 
		 * istream.close(); } catch (Exception ex) { System.err.println (ex); }
		 */

		return metaData;
	}

	/*
	 * public void cancel() throws Exception { try { System.err.println("SxSQL:
	 * Cancel statement"); statement.cancel(); } catch (Exception e) {
	 * System.err.println("SxSQL: Error canceling statement: " + e); } }
	 */

	/*
	 * public void cancel(String url, String user, String passwd) throws
	 * Exception { try { System.err.println("SxSQL: Cancel statement");
	 * statement.cancel(); } catch (Exception e) { System.err.println("SxSQL:
	 * Error canceling statement: " + e); } }
	 */

	static public void cancel() throws Exception {
		try {
			System.err.println("SxSQL: Cancel statement");
			// statement.cancel();
			ObjectInputStream inputFromServlet = null;
			ObjectOutputStream outputToServlet = null;

			servletConnection.disconnect();

		} catch (Exception e) {
			System.err.println("SxSQL: Error canceling statement: " + e);
		}
	}

	static public synchronized void close() {
		int proto_fkt_id = 4; // LOGOUT

		// prot_sql.replace( proto_id_pos, proto_id_pos + 1, (new
		// Integer(proto_fkt_id)).toString());
		System.out.println("in close");

		try {
			System.err.println("SxSQL: Closing db connection");
			if (!isClosed) {
				// execute(prot_sql.toString());

				if (resultSet != null)
					resultSet.close();
				if (statement != null)
					statement.close();

				ObjectInputStream inputFromServlet = null;
				ObjectOutputStream outputToServlet = null;

				servletConnection.disconnect();
				// Alter Rechte Bug - userID wurde beim Schließen der Connection
				// auf null gesetzt
				// wenn danach ein Programmteil getUserID() aufruft, wird nicht
				// null sondern
				// -1 zurückgeliefert
				// userID = null;
				// System.out.println(" SxSQl close: userID auf null gesetzt");
				isClosed = true;
			}
		} catch (SQLException e) {
			System.err.println("SxSQL: Error closing db connection: " + e);
		}
	}

	static public boolean isActive() {
		return !isClosed;
	}

	/**
	 * auf diese Methode sollte man sich eh nicht verlassen static protected
	 * void finalize() throws Throwable { if (!isClosed) { close(); userID =
	 * null; System.out.println(" SxSQl finalize: userID auf null gesetzt");
	 * isClosed = true; servletConnection.disconnect(); } }
	 * 
	 * @throws SQLException
	 */

	/**
	 * für freemarker zeugs, query wird wie üblich zum Hashtable hinzugefügt
	 * 
	 * @deprecated wegen Serialisierung doch nicht so gut ganzen Kram
	 *             rüberzuschicken
	 */
	static synchronized void specialExecute(String query, Hashtable htable)
			throws SQLException {
		PrintWriter outTest = null;
		BufferedReader inTest = null;
		Vector superX_elVector = new Vector();
		htable.put("query", query);
		try {

			servletConnection = (HttpURLConnection) superXDbServletUrl
					.openConnection();
			servletConnection.setDoInput(true);
			servletConnection.setDoOutput(true);

			// Don't used a cached version of URL connection.
			servletConnection.setUseCaches(false);

			// Specify the content type that we will send binary data
			servletConnection.setRequestProperty("Content-Type",
					"application/octet-stream");

		} catch (Exception e) {
			System.out.println(e.toString());
			throw new SQLException(e.toString());
		}

		rows_ret = new Vector();

		// Query übergeben

		try {
			// send the SuperX_el object to the servlet using serialization

			outputToServlet = new ObjectOutputStream(
					servletConnection.getOutputStream());

			outputToServlet.writeObject(htable);
			outputToServlet.flush();
			outputToServlet.close();

		} catch (IOException e) {
			System.out.println(e.toString());
			throw new SQLException(e.toString());
		} catch (Exception e) {
			e.printStackTrace();
			throw new SQLException(e.toString());
		}

		// Read the input from the servlet.
		//
		// The servlet will return a serialized vector containing
		// SuperX_el entries.
		//
		// System.out.println("Getting input stream");

		// output lesen
		ObjectInputStream inputFromServlet = null;
		try {
			inputFromServlet = new ObjectInputStream(
					servletConnection.getInputStream());
			gesamt = (SuperX_el) inputFromServlet.readObject();
			aktuelleNachricht = gesamt.getAktuelleNachricht();
			// System.out.println("Nachricht:"+aktuelleNachricht);

			// if (ErrorString.length()>1) System.out.println("Fehlermeld. vom
			// Servlet:"+ErrorString);
			numberOfColumns = gesamt.getColumnCount();
			// columnNames = gesamt.getColumnNames();
			rows = gesamt.getResultSet();
			metaData = new SxSQLMetaData(gesamt);
			inputFromServlet.close();

		} catch (Exception e) {
			e.printStackTrace();
			System.err.println(gesamt.getError_String()); // Wint
			throw new SQLException(gesamt.getError_String());
		}
		// System.out.println( "nach Rueckgabe Vector in Applet!!" );
		errorString = "" + gesamt.getError_String();
		if (errorString != null && errorString.trim().length() > 1) {
			if ((logToKonsole.equals("errors") || logToKonsole.equals("all"))
					&& aktuelleNachricht != null) {
				System.out
						.println("----------------------------------------------------");
				System.out.println("Folgender Select ergab einen Fehler: ");
				System.out.println(aktuelleNachricht);
				// System.out.println(logquery);
				System.out
						.println("----------------------------------------------------");

			}
			// Bei Fehlern in der Abfrage wird die Verbindung beendet, um
			// temporäre Tabellen zu löschen
			servletConnection.disconnect();
			throw new SQLException("im Servlet " + gesamt.getError_String());
		}
	}

	static private synchronized void applet_servlet_connection(String query)
			throws SQLException {
		String logquery = query.trim();
		if (logquery.substring(0, 6).equals("single"))
			logquery = query.substring(6);
		if (logquery.substring(0, 6).equals("multi:"))
			logquery = query.substring(6);
		// Anmeldedaten nicht im log zeigen
		if (logquery.startsWith("Anmeldung"))
			logquery = "Anmeldung";
		if (logToKonsole.equals("all")) {
			System.out.println("----------------Select-Stmt, gestartet am "
					+ SxDate.getNowString() + "-----------------");
			System.out.println(logquery);
			// System.out.println("----------------------------------------------------");
		}
		PrintWriter outTest = null;
		BufferedReader inTest = null;
		DataOutputStream printout;
		Vector superX_elVector = new Vector();
		rows_ret = new Vector();

		// aus Anmeldung|superx|anfang12
		// werden request param und query nur "Anmeldung"
		if (query.startsWith("Anmeldung")) {
			List l = StringUtils.getStringTokenizedList(query, "|");
			try {
				servletConnection =
				// (HttpURLConnection) new
				// URL(superXDbServletUrl.toString()+"?kennung="+l.get(1)+"&passwort="+l.get(2)).openConnection();
				(HttpURLConnection) new URL(superXDbServletUrl.toString())
						.openConnection();
				query = "Anmeldung";
				servletConnection.setRequestProperty("Content-Type",
						"application/x-www-form-urlencoded");
				servletConnection.setDoInput(true);
				servletConnection.setDoOutput(true);

				// Don't used a cached version of URL connection.
				servletConnection.setUseCaches(false);

				// Send POST output.
				printout = new DataOutputStream(
						servletConnection.getOutputStream());
				// System.out.println("Anmeldung für User "+ l.get(1) );
				String content = "kennung=" + l.get(1) + "&passwort="
						+ l.get(2) + "&MandantenID=" + mandantenID + "&query="
						+ query;
				printout.writeBytes(content);
				printout.flush();
				printout.close();
				// System.out.println("Anfrage für User "+ l.get(1)+ "
				// gesendet");

			} catch (Exception e) {
				e.printStackTrace();
				throw new SQLException(e.toString());
			}
		} else {
			try {
				servletConnection = (HttpURLConnection) new URL(
						superXDbServletUrl.toString() + ";jsessionid="
								+ jsessionid).openConnection();
				// Specify the content type that we will send binary data
				servletConnection.setRequestProperty("Content-Type",
						"application/octet-stream");
				servletConnection.setDoInput(true);
				servletConnection.setDoOutput(true);

				// Don't used a cached version of URL connection.
				servletConnection.setUseCaches(false);
				// send the SuperX_el object to the servlet using serialization

				outputToServlet = new ObjectOutputStream(
						servletConnection.getOutputStream());

				// serialize the object
				// Hashtable htable=new Hashtable();
				// htable.put("query",query);

				outputToServlet.writeObject(mandantenID);
				// 3/2016 Umlaut kodierung
				query = encodeUmlauts(query);
				String queryCode = de.memtext.util.CryptUtils
				// .simpleEncryptString2(query);
						.encryptStringDES(query);
				outputToServlet.writeObject(queryCode);
				String signature = null;
				if (dsaHandler != null) {
					signature = dsaHandler.sign(queryCode);
				}
				outputToServlet.writeObject(signature);
				// outputToServlet.writeObject(htable);
				outputToServlet.flush();
				outputToServlet.close();
			} catch (IOException e) {
				System.out.println(e.toString());
				throw new SQLException(e.toString());
			} catch (Exception e) {
				e.printStackTrace();
				throw new SQLException(e.toString());
			}
		}

		// Query übergeben

		// Read the input from the servlet.
		//
		// The servlet will return a serialized vector containing
		// SuperX_el entries.
		//
		// System.out.println("Getting input stream");

		// output lesen
		ObjectInputStream inputFromServlet = null;
		// System.out.println("Response vom Server lesen" );

		try {
			inputFromServlet = new ObjectInputStream(
					servletConnection.getInputStream());
			// System.out.println("Response vom Server gelesen" );

			gesamt = (SuperX_el) inputFromServlet.readObject();
			decodeUmlauts();
			jsessionid = gesamt.getJsessionid();

			aktuelleNachricht = gesamt.getAktuelleNachricht();
			// System.out.println("Nachricht:"+aktuelleNachricht);

			// if (ErrorString.length()>1) System.out.println("Fehlermeld. vom
			// Servlet:"+ErrorString);
			numberOfColumns = gesamt.getColumnCount();
			// columnNames = gesamt.getColumnNames();
			rows = gesamt.getResultSet();
			metaData = new SxSQLMetaData(gesamt);
			inputFromServlet.close();

		} catch (Exception e) {
			String msg = gesamt.getError_String();
			if (e instanceof java.io.StreamCorruptedException)
				msg = "Anmeldefehler (falsche jsessionid?!) " + msg;
			e.printStackTrace();
			System.err.println(); // Wint
			throw new SQLException(msg);
		}
		// System.out.println( "nach Rueckgabe Vector in Applet!!" );
		errorString = "" + gesamt.getError_String();
		if (errorString != null && errorString.trim().length() > 1) {
			if ((logToKonsole.equals("errors") || logToKonsole.equals("all"))
					&& aktuelleNachricht != null) {
				System.out
						.println("----------------------------------------------------");
				System.out.println("Folgender Select ergab einen Fehler: ");
				System.out.println(aktuelleNachricht);
				// System.out.println(logquery);
				System.out
						.println("----------------------------------------------------");

			}
			// Bei Fehlern in der Abfrage wird die Verbindung beendet, um
			// temporäre Tabellen zu löschen
			servletConnection.disconnect();
			throw new SQLException("im Servlet " + gesamt.getError_String());
		}

	}

	public static void decodeUmlauts() {
		gesamt.setError_String(decodeUmlauts(gesamt.getError_String()));
		gesamt.setAktuelleNachricht(decodeUmlauts(gesamt.getAktuelleNachricht()));
		gesamt.setRuntimeMessage(decodeUmlauts(gesamt.getRuntimeMessage()));
		String[] colLabels = gesamt.getColumnLabels();
		for (int i = 0; i < colLabels.length; i++) {
			colLabels[i] = decodeUmlauts(colLabels[i]);

		}
		gesamt.setColumnLabels(colLabels);
		SxResultSet rs = gesamt.getResultSet();
		for (Iterator it = rs.iterator(); it.hasNext();) {
			SxResultRow row = (SxResultRow) it.next();
			int i = 0;
			for (Iterator it2 = row.iterator(); it2.hasNext();) {
				Object o = it2.next();
				if (o instanceof String)
				{	o = decodeUmlauts(o.toString());
				row.set(i, o);
				}
				i++;

			}

		}
	}

	private static String decodeUmlauts(String txt) {
		if (txt != null) {
			txt = StringUtils.replace(txt, "///oe///", "ö");
			txt = StringUtils.replace(txt, "///Oe///", "Ö");
			txt = StringUtils.replace(txt, "///ae///", "ä");
			txt = StringUtils.replace(txt, "///Ae///", "Ä");
			txt = StringUtils.replace(txt, "///ue///", "ü");
			txt = StringUtils.replace(txt, "///Ue///", "Ü");
			txt = StringUtils.replace(txt, "///ss///", "ß");
		}
		return txt;
	}

	static String encodeUmlauts(String query) {
		query = StringUtils.replace(query, "ö", "///oe///");
		query = StringUtils.replace(query, "Ö", "///Oe///");
		query = StringUtils.replace(query, "ä", "///ae///");
		query = StringUtils.replace(query, "Ä", "///Ae///");
		query = StringUtils.replace(query, "ü", "///ue///");
		query = StringUtils.replace(query, "Ü", "///Ue///");
		query = StringUtils.replace(query, "ß", "///ss///");
		return query;
	}

	static void setUrl(String url) throws MalformedURLException {
		superXDbServletUrl = new URL(url);
	}

	static public String getErrorString() {
		return errorString;
	}

	/**
	 * nur von SuperX.start() aufgerufen
	 * 
	 * @param userID
	 *            The userID to set.
	 */
	public static void setUserID(Integer userID) {
		SxSQL.userID = userID;
	}

	public static void setLogMode(String logParam) {
		logToKonsole = logParam;
	}

	public static String getUserFromServlet() throws SQLException {

		executeQuery("get_user");
		SxResultRow row = (SxResultRow) gesamt.getResultSet().first();
		String user = (String) row.get(0);

		return user;
	}

	/**
	 * Aufruf von SuperX.start und auch noch mal von SxSQL.checkPwd (am Ende) um
	 * auch bei Applicationstart dafür zu sorgen, dass privateKey geholt wird
	 * 
	 * @throws Exception
	 */
	public static void initParams() throws Exception {
		executeQuery("get_params");
		String privateKeyEncoded = gesamt.getCheckval();
		if (privateKeyEncoded != null && !privateKeyEncoded.trim().equals("")) {
			privateKeyEncoded = CryptUtils.decryptStringDES(privateKeyEncoded);
			dsaHandler = new DSAHandler(privateKeyEncoded);
		} else
			dsaHandler = null;
		newPasswordChecker = gesamt.newPasswordChecker;
	}
}