/**
 * 
 */
package org.testcase;

import java.io.IOException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Date;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.sql.DataSource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * @author e323296
 *
 */
public class TestServlet extends HttpServlet {

	public final long SLEEP_TIMEOUT = 20000;

	/**
	 * 
	 */
	private static final long serialVersionUID = 239797250861048720L;
	private Log logger = LogFactory.getLog(TestServlet.class);
	private DataSource mySNonTXDatasource;


	/* (non-Javadoc)
	 * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
	 */
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
	throws ServletException {
		logger.info("TestServlet - Get request ...");

		String whichTest = "none";
		HttpSession session = req.getSession(true);

		try {
			datasourcesLookup();

			whichTest = (String) req.getParameter("test");
			if( whichTest == null || "".equals(whichTest) ) {
				logger.error("No parameter test defined !");
				throw new RuntimeException("No parameter test defined !");
			}

			logger.info("---> Request for lauching test case "+whichTest+"("+new Date()+")");

			session.setAttribute("whichTest", whichTest);
			session.setAttribute("exception", "none");

			try {
				Method[] methods = TestServlet.class.getDeclaredMethods();
				if( methods == null || methods.length == 0 ) {
					logger.error("No method found for this servlet !!!");
					throw new RuntimeException("No method found for this servlet !!!");
				}

				boolean foundMethod = false;
				for( Method method : methods ) {
					if( ("testUseCase_"+whichTest).equals(method.getName()) ) {
						foundMethod = true;
						method.invoke(this, new Object[] {req, resp} );
						break;
					}
				}

				if( !foundMethod ) {
					logger.error("Invalid value for the parameter test found !");
					throw new RuntimeException("Invalid value for the parameter test found !");
				}

				resp.sendRedirect(req.getContextPath() + "/ok/ok_test"+whichTest+".jsp");
			} catch (Exception e) {
				logger.error("Servlet has failed (see logs above)!");
				session.setAttribute("exception", e.getMessage());
				try {
					resp.sendRedirect(req.getContextPath() + "/ko/ko_test"+whichTest+".jsp");
				} catch (IOException e1) {
					logger.error("Redirect has failed and this will be ignored ...\n"+e1.getMessage());
				}
			}
		} catch( NamingException ne ) {
			logger.error("A Naming Exception occurred !");
			session.setAttribute("exception", ne.getMessage());
			try {
				resp.sendRedirect(req.getContextPath() + "/ko/ko_test"+whichTest+".jsp");
			} catch (IOException e1) {
				logger.error("Redirect has failed and this will be ignored ...\n"+e1.getMessage());
			}
		} finally {
			datasourceRelease();
			logger.info("---> End of test case "+whichTest+"("+new Date()+")");
		}
	}


	/**
	 * Release all reference to the datasource looked up
	 */
	private void datasourceRelease() {
		mySNonTXDatasource = null;
	}

	/**
	 * Retrieves all the datasource from JNDI
	 * 
	 * @throws NamingException
	 */
	private void datasourcesLookup() throws NamingException {
		Context ctx;
		ctx = new InitialContext();

		try {
			mySNonTXDatasource = (DataSource)ctx.lookup("java:comp/env/jdbc/Datasource_NonTX_S");
			logger.info("Non TX Shareable datasource lookup OK !");
		} catch (NamingException e) {
			logger.error("Naming Exception when binding the Non TX Shareable datasource.", e);
			throw e;
		}
	}

	/**
	 * @return
	 * @throws SQLException
	 */
	private Connection getShareableNonTxConnection() throws SQLException {
		Connection connSNonTx = null;
		try {
			connSNonTx = mySNonTXDatasource.getConnection();
			logger.info("Get shareable Non Tx connection ... OK");
		} catch (SQLException e) {
			logger.error("Get shareable Non Tx connection ... KO\n", e);
			throw e;
		}
		return connSNonTx;
	}

	/**
	 * @param connNonTX
	 * @throws SQLException
	 */
	private void closeNonTxConnection(Connection connNonTX) throws SQLException {
		if( connNonTX != null ) {
			try {
				connNonTX.close();
				logger.info("Close Non Tx connection ... OK");
			} catch (SQLException e) {
				logger.error("Close Non Tx connection ... KO\n", e);
				throw e;
			}
		}
	}


	/**
	 * 
	 */
	private void justSleeping() {
		try {
			Thread.sleep(SLEEP_TIMEOUT);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}



	/**
	 * Test 12a: Get four shareable non Tx connection in a row, test them and look at the monitoring
	 * 
	 * @param req
	 * @param resp
	 * @throws IOException
	 * @throws SQLException
	 */
	@SuppressWarnings("unused")
	private void testUseCase_12a(HttpServletRequest req, HttpServletResponse resp) throws Exception {

		Connection connNonTx1 = null;
		Connection connNonTx2 = null;
		Connection connNonTx3 = null;
		Connection connNonTx4 = null;
		
		try {
			connNonTx1 = getShareableNonTxConnection();
			TestCaseUtils.testChangeIsolationLevel("Test Case 12a (NonTx1)", connNonTx1);
			TestCaseUtils.testConnection(connNonTx1);

			connNonTx2 = getShareableNonTxConnection();
			TestCaseUtils.testChangeIsolationLevel("Test Case 12a (NonTx2)", connNonTx2);
			TestCaseUtils.testConnection(connNonTx2);

			connNonTx3 = getShareableNonTxConnection();
			TestCaseUtils.testChangeIsolationLevel("Test Case 12a (NonTx3)", connNonTx3);
			TestCaseUtils.testConnection(connNonTx3);

			connNonTx4 = getShareableNonTxConnection();
			TestCaseUtils.testChangeIsolationLevel("Test Case 12a (NonTx4)", connNonTx4);
			TestCaseUtils.testConnection(connNonTx4);

			justSleeping();
		} catch( Exception e ) {
			logger.error("Stopping test case since an unexpected exception occurred !");
			throw e;
		} finally {
			closeNonTxConnection(connNonTx1);
			closeNonTxConnection(connNonTx2);
			closeNonTxConnection(connNonTx3);
			closeNonTxConnection(connNonTx4);
		}
	}


}
