/*******************************************************************************
* Copyright 2017 Capital One Services, LLC and Bitwise, Inc.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package hydrograph.ui.graph.job;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import javax.websocket.Session;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Path;
import org.slf4j.Logger;
import hydrograph.ui.common.interfaces.parametergrid.DefaultGEFCanvas;
import hydrograph.ui.common.util.Constants;
import hydrograph.ui.graph.Messages;
import hydrograph.ui.graph.execution.tracking.connection.HydrographServerConnection;
import hydrograph.ui.graph.execution.tracking.replay.ViewExecutionHistoryUtility;
import hydrograph.ui.graph.execution.tracking.utils.TrackingDisplayUtils;
import hydrograph.ui.graph.handler.JobHandler;
import hydrograph.ui.graph.handler.StopJobHandler;
import hydrograph.ui.graph.utility.JobScpAndProcessUtility;
import hydrograph.ui.graph.utility.ViewDataUtils;
import hydrograph.ui.joblogger.JobLogger;
import hydrograph.ui.logging.factory.LogFactory;
/**
* The Class DebugRemoteJobLauncher run the job on remote server in debug mode.
*/
public class DebugRemoteJobLauncher extends AbstractJobLauncher{
/** The logger. */
private static Logger logger = LogFactory.INSTANCE.getLogger(DebugRemoteJobLauncher.class);
/** The Constant BUILD_SUCCESSFUL. */
private static final String BUILD_SUCCESSFUL = "BUILD SUCCESSFUL";
/** The Constant JOB_KILLED_SUCCESSFULLY. */
private static final String JOB_KILLED_SUCCESSFULLY = "JOB KILLED SUCCESSFULLY";
/** The Constant JOB_COMPLETED_SUCCESSFULLY. */
private static final String JOB_COMPLETED_SUCCESSFULLY = "JOB COMPLETED SUCCESSFULLY";
private static final String JOB_FAILED="JOB FAILED";
/**
* Run the job on remote server in debug mode.
*
* @param xmlPath
* @param debugXmlPath
* @param paramFile
* @param job
* @param gefCanvas
* @param externalSchemaFiles list required to move external schema files on remote server
* @param subJobList list required to move sub job xml to remote server.
*
*
*/
@Override
public void launchJobInDebug(String xmlPath, String debugXmlPath,
String paramFile,String userFunctionsPropertyFile, Job job,
DefaultGEFCanvas gefCanvas,List<String> externalSchemaFiles,List<String> subJobList) {
Session session=null;
if(isExecutionTrackingOn()){
HydrographServerConnection hydrographServerConnection = new HydrographServerConnection();
session = hydrographServerConnection.connectToServer(job, job.getUniqueJobId(),
TrackingDisplayUtils.INSTANCE.getWebSocketRemoteUrl(job));
if(hydrographServerConnection.getSelection() == 1){
return;
}
}
String projectName = xmlPath.split("/", 2)[0];
IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
job.setJobProjectDirectory(project.getLocation().toOSString());
String gradleCommand;
job.setJobStatus(JobStatus.RUNNING);
gradleCommand = JobScpAndProcessUtility.INSTANCE.getCreateDirectoryCommand(job,paramFile,xmlPath,projectName,externalSchemaFiles,subJobList);
enableLockedResources(gefCanvas);
JobLogger joblogger = initJobLogger(gefCanvas,job.getUniqueJobId());
executeCommand(job, project, gradleCommand, gefCanvas,joblogger);
JobManager.INSTANCE.enableRunJob(false);
if (JobStatus.FAILED.equals(job.getJobStatus())) {
releaseResources(job, gefCanvas, joblogger);
ViewExecutionHistoryUtility.INSTANCE.addTrackingJobs(job.getConsoleName(), job);
TrackingDisplayUtils.INSTANCE.closeWebSocketConnection(session);
return;
}
if (JobStatus.KILLED.equals(job.getJobStatus())) {
ViewExecutionHistoryUtility.INSTANCE.addTrackingJobs(job.getConsoleName(), job);
TrackingDisplayUtils.INSTANCE.closeWebSocketConnection(session);
return;
}
/*
* Created list having relative and absolute # separated path,
* the path is split in gradle script,Using absolute path we move the schema file to relative path directory of remote server
*/
if(!subJobList.isEmpty()){
List<String> subJobFullPath = new ArrayList<>();
for (String subJobFile : subJobList) {
subJobFullPath.add(subJobFile+"#"+JobManager.getAbsolutePathFromFile(new Path(subJobFile)).replace(Constants.JOB_EXTENSION, Constants.XML_EXTENSION));
}
gradleCommand = JobScpAndProcessUtility.INSTANCE.getSubjobScpCommand(subJobFullPath,job);
executeCommand(job, project, gradleCommand, gefCanvas,joblogger);
if (JobStatus.FAILED.equals(job.getJobStatus())) {
releaseResources(job, gefCanvas, joblogger);
ViewExecutionHistoryUtility.INSTANCE.addTrackingJobs(job.getConsoleName(), job);
TrackingDisplayUtils.INSTANCE.closeWebSocketConnection(session);
return;
}
if (JobStatus.KILLED.equals(job.getJobStatus())) {
ViewExecutionHistoryUtility.INSTANCE.addTrackingJobs(job.getConsoleName(), job);
TrackingDisplayUtils.INSTANCE.closeWebSocketConnection(session);
return;
}
}
/*
* Created list having relative and absolute # separated path,
* the path is split in gradle script using, absolute path we move the schema file to relative path (directory created using create directory command on remote server)
*/
if(!externalSchemaFiles.isEmpty()){
List<String> schemaFilesFullPath = new ArrayList<>();
for (String schemaFile : externalSchemaFiles) {
schemaFilesFullPath.add(schemaFile+"#"+JobManager.getAbsolutePathFromFile(new Path(schemaFile)));
}
gradleCommand = JobScpAndProcessUtility.INSTANCE.getSchemaScpCommand(schemaFilesFullPath,job);
executeCommand(job, project, gradleCommand, gefCanvas,joblogger);
if (JobStatus.FAILED.equals(job.getJobStatus())) {
releaseResources(job, gefCanvas, joblogger);
ViewExecutionHistoryUtility.INSTANCE.addTrackingJobs(job.getConsoleName(), job);
TrackingDisplayUtils.INSTANCE.closeWebSocketConnection(session);
return;
}
if (JobStatus.KILLED.equals(job.getJobStatus())) {
ViewExecutionHistoryUtility.INSTANCE.addTrackingJobs(job.getConsoleName(), job);
TrackingDisplayUtils.INSTANCE.closeWebSocketConnection(session);
return;
}
}
// ---------------------------- code to copy jar file
gradleCommand = JobScpAndProcessUtility.INSTANCE.getLibararyScpCommand(job);
executeCommand(job, project, gradleCommand, gefCanvas,joblogger);
if (JobStatus.FAILED.equals(job.getJobStatus())) {
releaseResources(job, gefCanvas, joblogger);
ViewExecutionHistoryUtility.INSTANCE.addTrackingJobs(job.getConsoleName(), job);
TrackingDisplayUtils.INSTANCE.closeWebSocketConnection(session);
return;
}
if (JobStatus.KILLED.equals(job.getJobStatus())) {
ViewExecutionHistoryUtility.INSTANCE.addTrackingJobs(job.getConsoleName(), job);
TrackingDisplayUtils.INSTANCE.closeWebSocketConnection(session);
return;
}
// ----------------------------- Code to copy job xml
gradleCommand = JobScpAndProcessUtility.INSTANCE.getJobXMLScpCommand(xmlPath, debugXmlPath, job);
executeCommand(job, project, gradleCommand, gefCanvas,joblogger);
if (JobStatus.FAILED.equals(job.getJobStatus())) {
releaseResources(job, gefCanvas, joblogger);
ViewExecutionHistoryUtility.INSTANCE.addTrackingJobs(job.getConsoleName(), job);
TrackingDisplayUtils.INSTANCE.closeWebSocketConnection(session);
return;
}
if (JobStatus.KILLED.equals(job.getJobStatus())) {
ViewExecutionHistoryUtility.INSTANCE.addTrackingJobs(job.getConsoleName(), job);
TrackingDisplayUtils.INSTANCE.closeWebSocketConnection(session);
return;
}
// ----------------------------- Code to copy jar files of project's lib folder
gradleCommand = JobScpAndProcessUtility.INSTANCE.getScpCommandForMovingLibFolderJarFiles(job);
executeCommand(job, project, gradleCommand, gefCanvas,joblogger);
if (JobStatus.FAILED.equals(job.getJobStatus())) {
releaseResources(job, gefCanvas, joblogger);
ViewExecutionHistoryUtility.INSTANCE.addTrackingJobs(job.getConsoleName(), job);
return;
}
if (JobStatus.KILLED.equals(job.getJobStatus())) {
ViewExecutionHistoryUtility.INSTANCE.addTrackingJobs(job.getConsoleName(), job);
return;
}
// ----------------------------- Code to copy user-functions property file from resource folder
gradleCommand = JobScpAndProcessUtility.INSTANCE.getScpCommandForMovingUserFunctionsPropertyFile(job);
executeCommand(job, project, gradleCommand, gefCanvas,joblogger);
if (JobStatus.FAILED.equals(job.getJobStatus())) {
releaseResources(job, gefCanvas, joblogger);
ViewExecutionHistoryUtility.INSTANCE.addTrackingJobs(job.getConsoleName(), job);
return;
}
if (JobStatus.KILLED.equals(job.getJobStatus())) {
ViewExecutionHistoryUtility.INSTANCE.addTrackingJobs(job.getConsoleName(), job);
return;
}
// ----------------------------- Code to copy parameter file
gradleCommand = JobScpAndProcessUtility.INSTANCE.getParameterFileScpCommand(paramFile, job);
executeCommand(job, project, gradleCommand, gefCanvas,joblogger);
if (JobStatus.FAILED.equals(job.getJobStatus())) {
releaseResources(job, gefCanvas, joblogger);
ViewExecutionHistoryUtility.INSTANCE.addTrackingJobs(job.getConsoleName(), job);
TrackingDisplayUtils.INSTANCE.closeWebSocketConnection(session);
return;
}
if (JobStatus.KILLED.equals(job.getJobStatus())) {
ViewExecutionHistoryUtility.INSTANCE.addTrackingJobs(job.getConsoleName(), job);
TrackingDisplayUtils.INSTANCE.closeWebSocketConnection(session);
return;
}
// ----------------------------- Execute job
gradleCommand = JobScpAndProcessUtility.INSTANCE.getExecututeJobCommand(xmlPath, debugXmlPath, paramFile,userFunctionsPropertyFile, job);
job.setJobStatus(JobStatus.SSHEXEC);
executeCommand(job, project, gradleCommand, gefCanvas,joblogger);
if (JobStatus.FAILED.equals(job.getJobStatus())) {
releaseResources(job, gefCanvas, joblogger);
ViewExecutionHistoryUtility.INSTANCE.addTrackingJobs(job.getConsoleName(), job);
TrackingDisplayUtils.INSTANCE.closeWebSocketConnection(session);
return;
}
if (JobStatus.KILLED.equals(job.getJobStatus())) {
((StopJobHandler) RunStopButtonCommunicator.StopJob.getHandler()).setStopJobEnabled(false);
((JobHandler) RunStopButtonCommunicator.RunJob.getHandler()).setRunJobEnabled(true);
ViewExecutionHistoryUtility.INSTANCE.addTrackingJobs(job.getConsoleName(), job);
TrackingDisplayUtils.INSTANCE.closeWebSocketConnection(session);
return;
}
if(job.getJobStatus().equalsIgnoreCase(JobStatus.RUNNING) || job.getJobStatus().equalsIgnoreCase(JobStatus.SSHEXEC)
|| job.getJobStatus().equalsIgnoreCase(JobStatus.PENDING)){
job.setJobStatus(JobStatus.SUCCESS);
}
if (job.getCanvasName().equals(JobManager.INSTANCE.getActiveCanvas())) {
JobManager.INSTANCE.enableRunJob(true);
}
releaseResources(job, gefCanvas, joblogger);
ViewDataUtils.getInstance().addViewDataJobDetails(job.getConsoleName(), job);
ViewExecutionHistoryUtility.INSTANCE.addTrackingJobs(job.getConsoleName(), job);
TrackingDisplayUtils.INSTANCE.closeWebSocketConnection(session);
}
/**
* Release resources.
*
* @param job the job
* @param gefCanvas the gef canvas
* @param joblogger the joblogger
*/
private void releaseResources(Job job, DefaultGEFCanvas gefCanvas, JobLogger joblogger) {
enableLockedResources(gefCanvas);
refreshProject(gefCanvas);
joblogger.logJobEndInfo(job.getUniqueJobId(), "");
joblogger.close();
JobManager.INSTANCE.removeJob(job.getLocalJobID());
if (job.getCanvasName().equals(JobManager.INSTANCE.getActiveCanvas())) {
JobManager.INSTANCE.enableRunJob(true);
}
}
/**
* Execute command.
*
* @param job the job
* @param project the project
* @param gradleCommand the gradle command
* @param gefCanvas the gef canvas
* @param joblogger
*/
private void executeCommand(Job job, IProject project, String gradleCommand, DefaultGEFCanvas gefCanvas, JobLogger joblogger) {
ProcessBuilder processBuilder = JobScpAndProcessUtility.INSTANCE.getProcess(project, gradleCommand);
try {
Process process = processBuilder.start();
job.setLocalJobProcess(process);
JobManager.INSTANCE.addJob(job);
logProcessLogsAsynchronously(joblogger, process, job, gefCanvas);
} catch (IOException e) {
logger.debug("Unable to execute the job", e);
}
}
/**
* Log process logs asynchronously.
*
* @param joblogger the joblogger
* @param process the process
* @param job the job
* @param gefCanvas the gef canvas
*/
private void logProcessLogsAsynchronously(final JobLogger joblogger, final Process process, final Job job,
DefaultGEFCanvas gefCanvas) {
InputStream stream = process.getInputStream();
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(stream));
String line = null;
while ((line = reader.readLine()) != null) {
if (line.contains(Messages.CURRENT_JOB_ID)) {
try {
Long.parseLong((line.split("#")[1]).trim());
((StopJobHandler) RunStopButtonCommunicator.StopJob.getHandler()).setStopJobEnabled(true);
} catch (NumberFormatException e) {
logger.warn("Exception while setting Remote job processId- " + line.split("#")[1].trim(), e);
}
}
if (line.contains(Messages.GRADLE_TASK_FAILED) || line.contains(JOB_FAILED)) {
job.setJobStatus(JobStatus.FAILED);
}
if (JobStatus.KILLED.equals(job.getJobStatus())) {
((StopJobHandler) RunStopButtonCommunicator.StopJob.getHandler()).setStopJobEnabled(false);
((JobHandler) RunStopButtonCommunicator.RunJob.getHandler()).setRunJobEnabled(true);
JobManager.INSTANCE.killJob(job.getConsoleName(), gefCanvas);
joblogger.logMessage("Killing job with job remote process id: " + job.getRemoteJobProcessID());
break;
}
if (!line.contains(BUILD_SUCCESSFUL)) {
joblogger.logMessage(line);
}
}
} catch (IOException e) {
if (JobManager.INSTANCE.getRunningJobsMap().containsKey(job.getLocalJobID()))
logger.info("Error occured while reading run job log", e);
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
logger.error("Ignore the exception", e);
}
}
}
if (JobStatus.KILLED.equals(job.getJobStatus())) {
joblogger.logMessage(JOB_KILLED_SUCCESSFULLY);
releaseResources(job, gefCanvas, joblogger);
JobManager.INSTANCE.removeJob(job.getLocalJobID());
}
if (!JobStatus.KILLED.equals(job.getJobStatus()) && !JobStatus.FAILED.equals(job.getJobStatus())
&& !JobStatus.RUNNING.equals(job.getJobStatus())) {
joblogger.logMessage(JOB_COMPLETED_SUCCESSFULLY);
job.setJobStatus(JobStatus.SUCCESS);
JobManager.INSTANCE.enableRunJob(true);
}
if (JobStatus.FAILED.equals(job.getJobStatus())) {
joblogger.logMessage(JOB_FAILED);
}
}
@Override
public void launchJob(String xmlPath, String paramFile,String userFunctionsPropertyFile, Job job,
DefaultGEFCanvas gefCanvas,List<String> externalSchemaFiles,List<String> subJobList) {
}
@Override
public void killJob(Job jobToKill) {
JobScpAndProcessUtility.INSTANCE.killRemoteJobProcess(jobToKill);
}
}