net.grinder.engine.agent.LocalScriptTestDriveService.java Source code

Java tutorial

Introduction

Here is the source code for net.grinder.engine.agent.LocalScriptTestDriveService.java

Source

/* 
 * 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 net.grinder.engine.agent;

import net.grinder.common.GrinderProperties;
import net.grinder.communication.FanOutStreamSender;
import net.grinder.engine.common.ScriptLocation;
import net.grinder.lang.AbstractLanguageHandler;
import net.grinder.lang.Lang;
import net.grinder.util.AbstractGrinderClassPathProcessor;
import net.grinder.util.Directory;
import net.grinder.util.NetworkUtils;
import net.grinder.util.thread.Condition;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.Properties;

import static org.ngrinder.common.util.NoOp.noOp;

/**
 * Script validation service.
 *
 * It works on local instead of remote agent. The reason this class is located
 * in ngrinder-core is... some The Grinder core class doesn't have public
 * access..
 *
 * @author JunHo Yoon
 * @since 3.0
 */
public class LocalScriptTestDriveService {
    private static final Logger LOGGER = LoggerFactory.getLogger(LocalScriptTestDriveService.class);
    public static final int DEFAULT_TIMEOUT = 100;

    /**
     * Validate script with 100 sec timeout.
     *
     * @param base                 working directory
     * @param script               script file
     * @param eventSynchronisation condition for event synchronization
     * @param securityEnabled      if security is set or not.
     * @param hostString           hostString
     * @return File which stores validation result.
     */
    public File doValidate(File base, File script, Condition eventSynchronisation, boolean securityEnabled,
            String hostString) {
        return doValidate(base, script, eventSynchronisation, securityEnabled, hostString, getDefaultTimeout());
    }

    protected int getDefaultTimeout() {
        return DEFAULT_TIMEOUT;
    }

    /**
     * Validate script.
     *
     * @param base                 working directory
     * @param script               script file
     * @param eventSynchronisation condition for event synchronization
     * @param securityEnabled      if security is set or not.
     * @param hostString           hostString
     * @param timeout              timeout in sec.
     * @return File which stores validation result.
     */
    @SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter")
    public File doValidate(File base, File script, Condition eventSynchronisation, boolean securityEnabled,
            String hostString, final int timeout) {
        FanOutStreamSender fanOutStreamSender = null;
        ErrorStreamRedirectWorkerLauncher workerLauncher = null;
        boolean stopByTooMuchExecution = false;
        ByteArrayOutputStream byteArrayErrorStream = new ByteArrayOutputStream();
        File file = new File(base, "validation-0.log");
        try {

            fanOutStreamSender = new FanOutStreamSender(1);
            deleteLogs(base);

            AbstractLanguageHandler handler = Lang.getByFileName(script).getHandler();
            AbstractGrinderClassPathProcessor classPathProcessor = handler.getClassPathProcessor();
            GrinderProperties properties = new GrinderProperties();
            PropertyBuilder builder = new PropertyBuilder(properties, new Directory(base), securityEnabled,
                    hostString, NetworkUtils.getLocalHostName());
            properties.setInt("grinder.agents", 1);
            properties.setInt("grinder.processes", 1);
            properties.setInt("grinder.threads", 1);
            properties.setBoolean("grinder.script.validation", true);
            String grinderJVMClassPath = classPathProcessor.buildForemostClasspathBasedOnCurrentClassLoader(LOGGER)
                    + File.pathSeparator + classPathProcessor.buildPatchClasspathBasedOnCurrentClassLoader(LOGGER)
                    + File.pathSeparator + builder.buildCustomClassPath(true);
            properties.setProperty("grinder.jvm.classpath", grinderJVMClassPath);
            LOGGER.info("grinder.jvm.classpath  : {} ", grinderJVMClassPath);
            AgentIdentityImplementation agentIdentity = new AgentIdentityImplementation("validation");
            agentIdentity.setNumber(0);
            String newClassPath = classPathProcessor.buildClasspathBasedOnCurrentClassLoader(LOGGER);
            LOGGER.debug("validation class path " + newClassPath);
            Properties systemProperties = new Properties();
            systemProperties.put("java.class.path", base.getAbsolutePath() + File.pathSeparator + newClassPath);

            Directory workingDirectory = new Directory(base);
            String buildJVMArgumentWithoutMemory = builder.buildJVMArgumentWithoutMemory();
            LOGGER.info("jvm args : {} ", buildJVMArgumentWithoutMemory);
            final WorkerProcessCommandLine workerCommandLine = new WorkerProcessCommandLine(properties,
                    systemProperties, buildJVMArgumentWithoutMemory, workingDirectory);

            ScriptLocation scriptLocation = new ScriptLocation(workingDirectory, script);
            ProcessWorkerFactory workerFactory = new ProcessWorkerFactory(workerCommandLine, agentIdentity,
                    fanOutStreamSender, false, scriptLocation, properties);

            workerLauncher = new ErrorStreamRedirectWorkerLauncher(1, workerFactory, eventSynchronisation, LOGGER,
                    byteArrayErrorStream);

            // Start
            workerLauncher.startAllWorkers();
            // Wait for a termination event.
            synchronized (eventSynchronisation) {
                final long sleep = 1000;
                int waitingCount = 0;
                while (true) {
                    if (workerLauncher.allFinished()) {
                        break;
                    }
                    if (waitingCount++ > timeout) {
                        LOGGER.error("Validation should be performed within {} sec. Stop it by force", timeout);
                        workerLauncher.destroyAllWorkers();
                        stopByTooMuchExecution = true;
                        break;
                    }
                    eventSynchronisation.waitNoInterrruptException(sleep);
                }
            }
        } catch (Exception e) {
            LOGGER.error("Error while executing {} because {}", script, e.getMessage());
            LOGGER.info("The error detail is ", e);
            appendingMessageOn(file, ExceptionUtils.getFullStackTrace(e));
        } finally {
            if (workerLauncher != null) {
                workerLauncher.shutdown();
            }
            if (fanOutStreamSender != null) {
                fanOutStreamSender.shutdown();
            }
            // To be safe, wait again..
            int waitingCount = 0;
            while (workerLauncher != null) {
                final int maximumWaitingCount = 10;
                if (workerLauncher.allFinished() || waitingCount++ > maximumWaitingCount) {
                    break;
                }
                synchronized (eventSynchronisation) {
                    eventSynchronisation.waitNoInterrruptException(1000);
                }
            }

        }
        appendingMessageOn(file, byteArrayErrorStream.toString());
        File errorValidation = new File(base, "error_validation-0.log");
        if (errorValidation.exists()) {
            String errorValidationResult = "";
            try {
                errorValidationResult = FileUtils.readFileToString(errorValidation);
            } catch (IOException e) {
                noOp();
            }
            appendingMessageOn(file, errorValidationResult);
        }
        if (stopByTooMuchExecution) {
            appendingMessageOn(file, "Validation should be performed within " + timeout + " sec. Stop it by force");
        }
        return file;
    }

    @SuppressWarnings("ResultOfMethodCallIgnored")
    private void deleteLogs(File base) {
        base.listFiles(new FileFilter() {
            @Override
            public boolean accept(File pathName) {
                String extension = FilenameUtils.getExtension(pathName.getName());
                if (extension.startsWith("log")) {
                    pathName.delete();
                }
                return true;
            }
        });
    }

    private void appendingMessageOn(File file, String msg) {
        FileWriter fileWriter = null;
        try {
            fileWriter = new FileWriter(file, true);
            fileWriter.append("\n\n").append(msg);
        } catch (IOException e) {
            LOGGER.error("Error during appending validation messages", e);
        } finally {
            IOUtils.closeQuietly(fileWriter);
        }
    }
}