/**********************************************************************
* Copyright (c) 2006 IBM Corporation and others.
* All rights reserved.   This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
* $Id: fileServer.c,v 1.2 2006/05/02 17:41:45 samwai Exp $
* 
* Contributors: 
* IBM - Initial API and implementation
**********************************************************************/

#include "fileServer.h"

tptp_int32 createFileServer(tptpJavaJob *job);
tptp_int32 createSecuredFileServer(tptpJavaJob *job);

tptp_uint32 startFileServer(tl_state_data_t* stateData, TID *tid) {
	/* First get the file server running , we can then get the file */
	int rc = tptpSubmitJavaJob(stateData, createFileServer, TRUE, tid);
	/* Now that the server is running, we can do our file transfer */
	if (rc == 0)
	{
/*		TPTP_LOG_INFO_MSG( stateData, "Insecure File Server started"); */
	}
	else {
		TPTP_LOG_WARNING_MSG( stateData, "Insecure File Server could not be started");
	}

	return 0;
}

tptp_uint32 startSecuredFileServer(tl_state_data_t* stateData, TID *tid) {
	/* First get the file server running , we can then get the file */
	int rc = tptpSubmitJavaJob(stateData, createSecuredFileServer, TRUE, tid);
	/* Now that the server is running, we can do our file transfer */
	if (rc == 0)
	{
/*		TPTP_LOG_INFO_MSG( stateData, "Secured File Server started"); */
	}
	else {
		TPTP_LOG_WARNING_MSG( stateData, "Secured File Server could not be started");
	}

	return 0;
}

tptp_int32 createFileServer(tptpJavaJob *job)
{
	jclass clazz;
	jmethodID			method;
	jobject				object;
	jclass				_fileServerClass;
	jobject				_fileServer;
	jobject				_fileServerObject;
	cctl_state_data_t*	cctlData;
	tl_state_data_t*	stateData;

	/* For checking the file server status */
	jint fileServerStatus = 0;
	jint errorCode  = 0;

	stateData = job->stateData;
	cctlData = (cctl_state_data_t*)stateData->implData;
	
	/* We first get the class ids of the classes we are interested in */

	if ((int)NULL == getcnvcls(job->env, CLASS_INSECURED_FILE_SERVER, strlen(CLASS_INSECURED_FILE_SERVER))) {
        TPTP_LOG_SEVERE_MSG1(stateData, "Could not find the file server class (%s).", CLASS_INSECURED_FILE_SERVER);
        return 0;
    }

	if ((int)NULL == getcnvcls(job->env, CLASS_INSECURED_FILE_SERVER_PARAMETERS, strlen(CLASS_INSECURED_FILE_SERVER_PARAMETERS))) {
        TPTP_LOG_SEVERE_MSG1(stateData, "Could not find the file server parameters class (%s).", CLASS_INSECURED_FILE_SERVER_PARAMETERS);
        return 0;
    }


	clazz=getcnvcls(job->env, CLASS_INSECURED_FILE_SERVER_PARAMETERS, strlen(CLASS_INSECURED_FILE_SERVER_PARAMETERS));
	_fileServerClass=getcnvcls(job->env, CLASS_INSECURED_FILE_SERVER, strlen(CLASS_INSECURED_FILE_SERVER));

	/* If we do not have this class, we cannot proceed */
	if (!clazz)	
	{
        TPTP_LOG_SEVERE_MSG1(stateData, "Could not get an ID for the file server parameters class (%s).", CLASS_INSECURED_FILE_SERVER_PARAMETERS);
		return 0;
	}
	
	/* If we do not have this class, we cannot proceed */
	if (!_fileServerClass)	
	{
        TPTP_LOG_SEVERE_MSG1(stateData, "Could not get an ID for the file server class (%s).", CLASS_INSECURED_FILE_SERVER);
		return 0;
	}

	/* We get the method id for the file server constructor*/
	/* Bug 64434 */
	method=getmthdid(job->env, _fileServerClass, "<init>", "()V");

	if (method)	
	{
		/* We now instantiate the File Server class using the default constructor */
		_fileServer=ENV(job->env)->NewObject(ENVPARM(job->env) _fileServerClass, method);
		/*Get a global reference to the File Server object */
		_fileServerObject=ENV(job->env)->NewGlobalRef(ENVPARM(job->env) _fileServer);

		/* Create an instance of the configuration class using the default constructor */
		object=ENV(job->env)->AllocObject(ENVPARM(job->env) clazz);

		if(object)
		{
			/* We set the port number for file transfer */
			/* Bug 64434 */
			method=getmthdid(job->env, clazz, "setPort", "(I)V");

			if (method)
				ENV(job->env)->CallVoidMethod(ENVPARM(job->env) object, method, cctlData->filePort);
			else
				TPTP_LOG_SEVERE_MSG(stateData, "Could not get ID for method setPort");


			/* We can now find the method id for init method */
			/* Bug 64434 */
			method=getmthdid(job->env, _fileServerClass, "init", METHOD_SIGNATURE_FILE_SERVER_PARAMETERS);
			if(method)
			{
				ENV(job->env)->CallVoidMethod(ENVPARM(job->env)_fileServer, method, object);

				/* We now find the method id for server run method */
				/* Bug 64434 */
				method=getmthdid(job->env, _fileServerClass, "run", "()V");

				/* and get the file server running */
				if (method)	/* Was successful */
				{
					ENV(job->env)->CallVoidMethod(ENVPARM(job->env)_fileServer, method);

					/* We have to check for the file server status after we get it running */
					method=getmthdid(job->env, _fileServerClass, "getFileServerStatus", "()I");

					if(method)
					{
						fileServerStatus = ENV(job->env)->CallIntMethod(ENVPARM(job->env)_fileServer, method, object);
						if (fileServerStatus != 0)	
						{
							/* We have an error... Try to determine the type of error */
							method = getmthdid(job->env, _fileServerClass, "getErrorType", "()I");

							if(method)
							{
								errorCode = ENV(job->env)->CallIntMethod(ENVPARM(job->env)_fileServer, method, object);
								if (errorCode == FILE_SERVER_SOCKET_BIND_EXCEPTION)	
								{
									/* We have a BindException in the file server */
									TPTP_LOG_SEVERE_MSG1(stateData, "The file server could not bind to the configured file port %d. Make sure the port is free and no other Agent Controller is using the same port.", cctlData->filePort);

								}
								else if (errorCode == FILE_SERVER_IO_EXCEPTION)
								{
									/* We have an IOException in the file server */
									TPTP_LOG_SEVERE_MSG(stateData, "The file server could not start because of an IOException");

								}
								else
								{
									/* We have an unknown error in the file server */
									TPTP_LOG_SEVERE_MSG(stateData, "The file server could not start");
								}
							}
							else
							{
								ENV(job->env)->ExceptionClear(ENVPARM1(job->env));
								TPTP_LOG_SEVERE_MSG(stateData, "Could not get ID for method getErrorType");
							}
						}
						else {
							TPTP_LOG_INFO_MSG1(stateData, "File server started listening on port %d", cctlData->filePort);
						}

					}
					else
					{
						ENV(job->env)->ExceptionClear(ENVPARM1(job->env));
						TPTP_LOG_SEVERE_MSG(stateData, "Could not get ID for method getFileServerStatus");
					}

				}
				else
				{
					ENV(job->env)->ExceptionClear(ENVPARM1(job->env));
					TPTP_LOG_SEVERE_MSG(stateData, "Could not get ID for method run");
				}
			}
			else
			{
				ENV(job->env)->ExceptionClear(ENVPARM1(job->env));
				TPTP_LOG_SEVERE_MSG(stateData, "Could not get ID for method init");

			}
		}
		else
		{
			ENV(job->env)->ExceptionClear(ENVPARM1(job->env));
			TPTP_LOG_SEVERE_MSG(stateData, "Could not allocate object for file server parameters class ");
		}
	}
	else
	{
		ENV(job->env)->ExceptionClear(ENVPARM1(job->env));
		TPTP_LOG_SEVERE_MSG(stateData, "Could not get ID for method file server constructor");
	}
	
	return 0;
}

tptp_int32 createSecuredFileServer(tptpJavaJob *job) {
	jclass classSecuredFileServer;
	jclass classSecuredFileServerParameters;
	jclass classString;
	jthrowable jexc;

	tptp_uint32		securedFilePort;
	tptp_string		*keystore;
	tptp_string		*keystorePassword;

	cctl_state_data_t*	cctlData;
	tl_state_data_t*	stateData;

	stateData = job->stateData;
	cctlData = (cctl_state_data_t*)stateData->implData;

	/* Fill up the required variables */
	securedFilePort = cctlData->filePort;
	keystore = cctlData->keystore;
	keystorePassword = cctlData->keystorePassword;


	/* Locate our Server configuration class */
	classSecuredFileServer = getcnvcls(job->env, CLASS_SECURED_FILE_SERVER, strlen(CLASS_SECURED_FILE_SERVER));
	classSecuredFileServerParameters = getcnvcls(job->env, CLASS_SECURED_FILE_SERVER_PARAMETERS, strlen(CLASS_SECURED_FILE_SERVER_PARAMETERS));
	classString = getcnvcls(job->env, CLASS_STRING, strlen(CLASS_STRING));

	if(classSecuredFileServer && classSecuredFileServerParameters && classString) {
		jobject objectSecuredFileServerParameters;
		jobject objectSecuredFileServer;

		/* Create an instance of the configuration class using the default constructor */
		objectSecuredFileServerParameters = ENV(job->env)->AllocObject(ENVPARM(job->env) classSecuredFileServerParameters);
		objectSecuredFileServer = ENV(job->env)->AllocObject(ENVPARM(job->env) classSecuredFileServer);
		/* Need a global reference for shutting down the secured server */
		g_objectSecuredFileServer = ENV(job -> env) -> NewGlobalRef(ENVPARM(job -> env) objectSecuredFileServer);

		if(objectSecuredFileServer && objectSecuredFileServerParameters) {
			jmethodID method;

			/* Lookup and invoke each method in turn */
			method = getmthdid(job -> env, classSecuredFileServerParameters, "setPort", "(I)V");
			if(method) {
				ENV(job->env)->CallVoidMethod(ENVPARM(job->env) objectSecuredFileServerParameters, method, securedFilePort);
/*				TPTP_LOG_INFO_MSG1(stateData, "Secured port set to %d", securedFilePort); */
			}
			else {
				ENV(job->env)->ExceptionClear(ENVPARM1(job->env));
				TPTP_LOG_SEVERE_MSG(stateData, "Could not get ID for method setPort()");
			}

			method = getmthdid(job -> env, classSecuredFileServerParameters, "setKeystoreFile", "(Ljava/lang/String;)V");
			if(method) {
				jstring value;
				value = getnewstrutf(job -> env, keystore);
				ENV(job->env)->CallVoidMethod(ENVPARM(job->env) objectSecuredFileServerParameters, method, value);
			}
			else {
				ENV(job->env)->ExceptionClear(ENVPARM1(job->env));
				TPTP_LOG_SEVERE_MSG(stateData, "Could not get ID for method setKeystoreFile()");
			}

			method = getmthdid(job -> env, classSecuredFileServerParameters, "setKeystorePassword", "(Ljava/lang/String;)V");
			if(method) {
				jstring value;
				value = getnewstrutf(job -> env, keystorePassword);
				ENV(job->env)->CallVoidMethod(ENVPARM(job->env) objectSecuredFileServerParameters, method, value);
			}
			else {
				ENV(job->env)->ExceptionClear(ENVPARM1(job->env));
				TPTP_LOG_SEVERE_MSG(stateData, "Could not get ID for method setKeystorePassword()");
			}

			method = getmthdid(job -> env, classSecuredFileServerParameters, "setKeystoreManager", "(Ljava/lang/String;)V");
			if(method) {
				jstring value;
				value = getnewstrutf(job -> env, CLASS_KEYSTORE_MANAGER);
				ENV(job->env)->CallVoidMethod(ENVPARM(job->env) objectSecuredFileServerParameters, method, value);
			}
			else {
				ENV(job->env)->ExceptionClear(ENVPARM1(job->env));
				TPTP_LOG_SEVERE_MSG(stateData, "Could not get ID for method setKeystoreManager()");
			}

			/* OK, we are good to start our server */
			method = getmthdid(job -> env, classSecuredFileServer, "init", METHOD_SIGNATURE_SECURED_FILE_SERVER_PARAMETERS);
			if(method) {
				ENV(job->env)->CallVoidMethod(ENVPARM(job->env) objectSecuredFileServer, method, objectSecuredFileServerParameters);

				/* This is to detect the exception on AS/400 when setWantClientAuth() is called. */
				if (jexc = ENV(job -> env) -> ExceptionOccurred(ENVPARM1(job -> env))) {
					ENV(job -> env)->ExceptionDescribe(ENVPARM1(job -> env));
					ENV(job -> env)->ExceptionClear(ENVPARM1(job -> env));
					TPTP_LOG_SEVERE_MSG(stateData, "Exception in init()");
				}

				method = getmthdid(job -> env, classSecuredFileServer, "run", "()V");
				if(method) {
					TPTP_LOG_INFO_MSG1(stateData, "Secured File Server started listening on port %d", securedFilePort);
					ENV(job->env)->CallVoidMethod(ENVPARM(job->env) objectSecuredFileServer, method);
				}
				else {
					ENV(job->env)->ExceptionClear(ENVPARM1(job->env));
					TPTP_LOG_SEVERE_MSG(stateData, "Could not get ID for method run()");
				}
			}
			else {
				ENV(job->env)->ExceptionClear(ENVPARM1(job->env));
				TPTP_LOG_SEVERE_MSG(stateData, "Could not get ID for method init");
			}
        }
		else if (objectSecuredFileServerParameters == (int)NULL) {
			ENV(job->env)->ExceptionClear(ENVPARM1(job->env));
			TPTP_LOG_SEVERE_MSG1(stateData, "Could not allocate object of class %s", CLASS_SECURED_FILE_SERVER_PARAMETERS);
		}
		else if (objectSecuredFileServer == (int)NULL) {
			ENV(job->env)->ExceptionClear(ENVPARM1(job->env));
			TPTP_LOG_SEVERE_MSG1(stateData, "Could not allocate object of class %s", CLASS_SECURED_FILE_SERVER);
		}
	}
	else {
		TPTP_LOG_SEVERE_MSG(stateData, "Could not find a java class. Secured File Server fails to start.");
	}

	return 0;
}
