package com.tsystems.etc.bpel;

import java.sql.*;
import javax.sql.DataSource;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import com.oracle.bpel.client.*;

/**
 * Hilfsklasse zur Fehlerbehandlung. Diese Klasse implementiert das Singleton-Pattern.
 */
public class FaultHandlerHelper {
	private static final FaultHandlerHelper HELPER = new FaultHandlerHelper();
	private FaultHandlerHelper() {}
	/**
	 * Liefert die Instanz dieser Klasse.
	 */
	public static FaultHandlerHelper getInstance() {
		return HELPER;
	}
	/**
	 * Speichert eine Fehlermeldung.
	 * 
	 * @param type Fehlertyp
	 * @param process Prozess, in dem der Fehler aufgetreten ist
	 * @param payload Nachricht, bei der der Fehler aufgetreten ist
	 * @param message Fehlermeldung
	 */
	public void store(String type, String host, Object process, Object payload, Object message) throws NamingException, SQLException {
		Connection con = null;
		PreparedStatement pstmt = null;
		try {
			InitialContext ctx = new InitialContext();
			DataSource ds = (DataSource)ctx.lookup("jdbc/FaultHandlerCoreDataSource");
			con = ds.getConnection();
			con.setAutoCommit(true);
			pstmt = con.prepareStatement(
				"INSERT INTO t_fault (fault_date, fault_type, fault_host, fault_process, fault_payload, fault_message) VALUES (?, ?, ?, ?, ?, ?)");
			pstmt.setTimestamp(1, new Timestamp(System.currentTimeMillis()));
			pstmt.setString(2, type);
			pstmt.setString(3, host);
			pstmt.setString(4, process != null ? process.toString() : null);
			pstmt.setString(5, payload != null ? payload.toString() : null);
			pstmt.setString(6, message != null ? message.toString() : null);
			pstmt.executeUpdate();
		} finally {
			if (pstmt != null) {
				try { pstmt.close(); }
				catch (SQLException ignore) {}
			}
			if (con != null) {
				try { con.close(); }
				catch (SQLException ignore) {}
			}
		}
	}
	/**
	 * Aktualisiert die Tagesanzahl des Auftretens eines Fehlers pro Prozess.
	 * 
	 * @param type Fehlertyp
	 * @param process Prozessname
	 * @return aktualisierte Fehleranzahl
	 */
	public synchronized int updateCount(String type, String host, Object process) throws NamingException, SQLException {
		Connection con = null;
		PreparedStatement pstmt = null;
		try {
			InitialContext ctx = new InitialContext();
			DataSource ds = (DataSource)ctx.lookup("jdbc/FaultHandlerCoreDataSource");
			con = ds.getConnection();
			con.setAutoCommit(true);
			Date date = new Date(System.currentTimeMillis());
			int count = 0;
			for (int i = 0; i <= 2; i++) {
				pstmt = con.prepareStatement(i != 2 ? i != 1 ? 
					"UPDATE t_fault_count SET fault_count=fault_count+1 WHERE fault_date=? AND fault_type=? AND fault_host=? AND fault_process=?" : 
					"INSERT INTO t_fault_count (fault_date, fault_type, fault_host, fault_process, fault_count) VALUES (?, ?, ?, ?, 1)" : 
					"SELECT fault_count FROM t_fault_count WHERE fault_date=? AND fault_type=? AND fault_host=? AND fault_process=?");
				pstmt.setDate(1, date);
				pstmt.setString(2, type);
				pstmt.setString(3, host);
				pstmt.setString(4, process != null ? process.toString() : null);
				pstmt.execute();
				if (i != 2) {
					if (pstmt.getUpdateCount() > 0) {
						i = 1;
					}
				} else {
					ResultSet res = pstmt.getResultSet();
					if (res.next()) {
						count = res.getInt(1);
					}
				}
				pstmt.close();
				pstmt = null;
			}
			return count;
		} finally {
			if (pstmt != null) {
				try { pstmt.close(); }
				catch (SQLException ignore) {}
			}
			if (con != null) {
				try { con.close(); }
				catch (SQLException ignore) {}
			}
		}
	}
	/**
	 * Setzt den Lebenszyklus eines Prozesses auf inaktiv, so dass keine neuen 
	 * Prozessinstanzen kreiert werden.
	 * 
	 * @param locator Locator zum Zugriff auf den Prozess
	 * @param process Prozessname
	 */
	public void retireProcess(Locator locator, Object process) throws ServerException {
		IBPELProcessHandle handle = locator.lookupProcess(String.valueOf(process));
		BPELProcessMetaData metaData = handle.getMetaData();
		metaData.setLifecycle(IBPELProcessConstants.LIFECYCLE_RETIRED);
		handle.updateMetaData(metaData);
	}
	/**
	 * Extrahiert den Host aus einer URL.
	 * 
	 * @param url URL in Form eines String-Objektes
	 */
	public String getHost(Object url) {
		String s = url.toString();
		int i = s.indexOf("://")+3, j = s.indexOf('/', i);
		return s.substring(i, j);
	}
}
