/******************************************************************************* * Copyright (c) 2004, 2010, 2013 BREDEX GmbH. * 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 * * Contributors: * BREDEX GmbH - initial API and implementation and/or initial documentation *******************************************************************************/ package org.eclipse.jubula.autagent.commands; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.jar.JarFile; import java.util.jar.Manifest; import org.apache.commons.lang.LocaleUtils; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.Platform; import org.eclipse.jubula.autagent.monitoring.IMonitoring; import org.eclipse.jubula.autagent.monitoring.MonitoringDataStore; import org.eclipse.jubula.autagent.monitoring.MonitoringUtil; import org.eclipse.jubula.communication.internal.message.StartAUTServerStateMessage; import org.eclipse.jubula.tools.internal.constants.AUTStartResponse; import org.eclipse.jubula.tools.internal.constants.AutConfigConstants; import org.eclipse.jubula.tools.internal.constants.CommandConstants; import org.eclipse.jubula.tools.internal.constants.MonitoringConstants; import org.eclipse.jubula.tools.internal.constants.StringConstants; import org.eclipse.jubula.tools.internal.jarutils.MainClassLocator; import org.eclipse.osgi.service.datalocation.Location; import org.osgi.framework.Bundle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author BREDEX GmbH * @created Jul 9, 2007 */ public abstract class AbstractStartJavaAut extends AbstractStartToolkitAut { /** * <code>JAVA_OPTIONS_INTRO</code> */ protected static final String JAVA_OPTIONS_INTRO = "_JAVA_OPTIONS="; //$NON-NLS-1$ /** * <code>JAVA_LANGUAGE_PROPERTY</code> */ private static final String JAVA_LANGUAGE_PROPERTY = "-Duser.language="; //$NON-NLS-1$ /** * <code>JAVA_COUNTRY_PROPERTY</code> */ private static final String JAVA_COUNTRY_PROPERTY = "-Duser.country="; //$NON-NLS-1$ /** the logger */ private static final Logger LOG = LoggerFactory.getLogger(AbstractStartJavaAut.class); /** * {@inheritDoc} */ protected String createBaseCmd(Map<String, String> parameters) throws IOException { String executableFileName = parameters.get( AutConfigConstants.EXECUTABLE); if (executableFileName != null && executableFileName.length() > 0) { // Use the given executable, prepending the working directory if // the filename is relative File exe = new File(executableFileName); if (!exe.isAbsolute()) { exe = new File( parameters.get(AutConfigConstants.WORKING_DIR), executableFileName); } if (exe.isFile() && exe.exists()) { return exe.getCanonicalPath(); } // else String errorMsg = executableFileName + " does not point to a valid executable."; //$NON-NLS-1$ LOG.warn(errorMsg); return executableFileName; } // Use java if no executable file is defined String java = StringConstants.EMPTY; String jre = parameters.get(AutConfigConstants.JRE_BINARY); if (jre == null) { jre = StringConstants.EMPTY; } File jreFile = new File(jre); if (jre.length() == 0) { java = "java"; //$NON-NLS-1$ } else { if (!jreFile.isAbsolute()) { jreFile = new File(getWorkingDir(parameters), jre); } if (jreFile.isFile() && jreFile.exists()) { java = jreFile.getCanonicalPath(); } else { String errorMsg = jreFile + " does not point to a valid JRE executable."; //$NON-NLS-1$ LOG.error(errorMsg); throw new FileNotFoundException(errorMsg); } } return java; } /** * Determines the main class for the AUT. <br> * If a main class was transmitted, use it. Otherwise scan the jar. * * @param parameters The parameters for starting the AUT. * @return the main class or null if no main class was found. In this case * m_errorMesssage contains a detailed message to send back. */ protected String getAUTMainClass(Map parameters) { final String jarFile = (String)parameters.get( AutConfigConstants.JAR_FILE); String mainClass = getMainClassFromManifest(parameters); if (mainClass != null) { return mainClass; } if (LOG.isInfoEnabled()) { LOG.info("neither main class transmitted nor found in the manifest, " //$NON-NLS-1$ + "searching in jar: '" //$NON-NLS-1$ + String.valueOf(jarFile) + "'"); //$NON-NLS-1$ } if (jarFile != null && jarFile.length() > 0) { try { List mains = MainClassLocator.getMainClass(new File(jarFile)); if (mains.size() == 0) { String message = "no main class found in '" //$NON-NLS-1$ + jarFile + "'"; //$NON-NLS-1$ LOG.error(message); setErrorMessage(new StartAUTServerStateMessage( AUTStartResponse.AUT_MAIN_NOT_FOUND_IN_JAR, message)); return null; } if (mains.size() != 1) { // the jar must contain exact one main class // HERE send back a list of main classes String message = "more than on main class found"; //$NON-NLS-1$ LOG.error(message); setErrorMessage(new StartAUTServerStateMessage( AUTStartResponse.AUT_MAIN_NOT_DISTINCT_IN_JAR, message)); return null; } return ((String)mains.get(0)).replace('/', '.'); } catch (NullPointerException npe) { // from new File() String message = "no jar given as classpath"; //$NON-NLS-1$ LOG.error(message, npe); setErrorMessage(new StartAUTServerStateMessage( AUTStartResponse.NO_JAR_AS_CLASSPATH, message)); return null; } catch (IOException ioe) { String message = "scanning '" //$NON-NLS-1$ + String.valueOf(jarFile) + "' for main class failed"; //$NON-NLS-1$ LOG.error(message, ioe); setErrorMessage(new StartAUTServerStateMessage( AUTStartResponse.SCANNING_JAR_FAILED, message)); return null; } } return null; } /** * Gets the main Class of the AUT jar * * @param parameters The parameters for starting the AUT. * @return the main class */ protected String getMainClassFromManifest(Map parameters) { String jarFile = createAbsoluteJarPath(parameters); return getAttributeFromManifest("main-class", jarFile); //$NON-NLS-1$ } /** * @param attributeName the attribute name in the manifest * @param jarFile the path and name of the jar file to examine * @return the String value of the specified attribute name, or null if * not found. */ protected String getAttributeFromManifest( String attributeName, String jarFile) { if (jarFile == null || jarFile.length() < 1) { return null; } String attribute = null; try (JarFile jar = new JarFile(jarFile)) { Manifest manifest = jar.getManifest(); if (manifest != null) { attribute = manifest.getMainAttributes().getValue( attributeName); } } catch (FileNotFoundException e) { LOG.error("File not found: " + jarFile, e); //$NON-NLS-1$ } catch (IOException e) { LOG.error("Error reading jar file: " + jarFile, e); //$NON-NLS-1$ } return attribute; } /** * * @param parameters The parameters for starting the AUT. * @return the absolute path to the AUT jar file or null. */ protected String createAbsoluteJarPath(Map parameters) { File workingDir = getWorkingDir(parameters); String jarPath = (String)parameters.get(AutConfigConstants.JAR_FILE); if (jarPath != null && jarPath.length() > 0) { if (workingDir != null) { File jarFile = new File(jarPath); if (!jarFile.isAbsolute()) { jarPath = workingDir + FILE_SEPARATOR + jarPath; } } } return jarPath; } /** * @return the name of the main class for the AUT server. */ protected abstract String getServerClassName(); /** * @param cmds The command List. May <b>not</b> be <code>null</code>. * @param locale The <code>Locale</code> for the AUT. * May be <code>null</code> if no locale was specified. */ protected void addLocale(List<String> cmds, Locale locale) { if (locale != null) { String country = locale.getCountry(); if (country != null && country.length() > 0) { cmds.add(JAVA_COUNTRY_PROPERTY + country); } String language = locale.getLanguage(); if (language != null && language.length() > 0) { cmds.add(JAVA_LANGUAGE_PROPERTY + language); } } } /** * Gets the classPath from the manifest of the given jar. * * @param parameters The parameters for starting the AUT. * @return the classpath separated with OS-specific path separators * or an empty String if the given jar is null or if there is no manifest * in the jar. */ protected String getClassPathFromManifest(Map parameters) { String jarFile = createAbsoluteJarPath(parameters); String classPath = getAttributeFromManifest("class-path", jarFile); //$NON-NLS-1$ if (classPath == null) { return StringConstants.EMPTY; } classPath = classPath.trim(); return classPath.replace(' ', PATH_SEPARATOR.charAt(0)); } /** * @param parameters The parameters for starting the AUT. * @return <code>true</code> if the AUT is being started via an executable * file or script. Otherwise, <code>false</code>. */ protected boolean isRunningFromExecutable(Map parameters) { return parameters.containsKey(AutConfigConstants.EXECUTABLE); } /** * Sets -javaagent and JRE arguments as SUN environment variable. * @param parameters The parameters for starting the AUT * @return the _JAVA_OPTIONS environment variable including -javaagent * and jre arguments */ protected String setJavaOptions(Map<String, String> parameters) { StringBuffer sb = new StringBuffer(); if (isRunningFromExecutable(parameters)) { Locale locale = LocaleUtils.toLocale(parameters .get(AutConfigConstants.AUT_LOCALE)); // set agent and locals sb.append(JAVA_OPTIONS_INTRO); if (org.eclipse.jubula.tools.internal.utils.MonitoringUtil .shouldAndCanRunWithMonitoring(parameters)) { String monAgent = getMonitoringAgent(parameters); if (monAgent != null) { sb.append(monAgent).append(StringConstants.SPACE); } } sb.append(StringConstants.QUOTE) .append("-javaagent:") //$NON-NLS-1$ .append(getAbsoluteAgentJarPath()) .append(StringConstants.QUOTE); if (locale != null) { sb.append(StringConstants.SPACE) .append(JAVA_COUNTRY_PROPERTY) .append(locale.getCountry()); sb.append(StringConstants.SPACE) .append(JAVA_LANGUAGE_PROPERTY) .append(locale.getLanguage()); } } else { if (org.eclipse.jubula.tools.internal.utils.MonitoringUtil .shouldAndCanRunWithMonitoring(parameters)) { String monAgent = getMonitoringAgent(parameters); if (monAgent != null) { sb.append(JAVA_OPTIONS_INTRO).append(monAgent); } } } return sb.toString(); } /** * Gets the absolute path of the org.eclipse.jubula.rc.common.agent.jar file. * @return the absolute path */ protected String getAbsoluteAgentJarPath() { return AbstractStartToolkitAut.getClasspathForBundleId( CommandConstants.RC_COMMON_AGENT_BUNDLE_ID); } /** * @return the AUTAgent installation directory */ public static File getInstallDir() { Location installLoc = Platform.getInstallLocation(); String installDir = installLoc.getURL().getFile(); return new File(installDir); } /** * This method will load the class which implements the {@link IMonitoring} * interface, and will invoke the "getAgent" method. * @param parameters The AutConfigMap * @return agentString The agent String like -javaagent:myagent.jar * or null if the monitoring agent String couldn't be generated */ protected String getMonitoringAgent(Map<String, String> parameters) { String autId = parameters.get( AutConfigConstants.AUT_ID); MonitoringDataStore mds = MonitoringDataStore.getInstance(); boolean duplicate = MonitoringUtil.checkForDuplicateAutID(autId); if (!duplicate) { mds.putConfigMap(autId, parameters); } String agentString = null; String monitoringImplClass = parameters.get( MonitoringConstants.AGENT_CLASS); String bundleId = parameters.get( MonitoringConstants.BUNDLE_ID); try { Bundle bundle = Platform.getBundle(bundleId); if (bundle == null) { LOG.error("No bundle was found for the given bundleId"); //$NON-NLS-1$ return null; } Class<?> monitoringClass = bundle.loadClass(monitoringImplClass); Constructor<?> constructor = monitoringClass.getConstructor(); IMonitoring agentInstance = (IMonitoring)constructor.newInstance(); agentInstance.setAutId(autId); //set the path to the agent jar file agentInstance.setInstallDir(FileLocator.getBundleFile(bundle)); agentString = agentInstance.createAgent(); if (!duplicate) { mds.putMonitoringAgent(autId, agentInstance); } } catch (InstantiationException e) { LOG.error("The instantiation of the monitoring class failed ", e); //$NON-NLS-1$ } catch (IllegalAccessException e) { LOG.error("Access to the monitoring class failed ", e); //$NON-NLS-1$ } catch (SecurityException e) { LOG.error("Access to the monitoring class failed ", e); //$NON-NLS-1$ } catch (NoSuchMethodException e) { LOG.error("A method in the monitoring class could not be found", e); //$NON-NLS-1$ } catch (IllegalArgumentException e) { LOG.error("A argument which is passed to monitoring class is invalide", e); //$NON-NLS-1$ } catch (InvocationTargetException e) { LOG.error("The method call of 'getAgent' failed, you have to implement the interface IMonitoring", e); //$NON-NLS-1$ } catch (ClassNotFoundException e) { LOG.error("The monitoring class can not be found", e); //$NON-NLS-1$ } catch (IOException e) { LOG.error("IOException while searching for the given bundle", e); //$NON-NLS-1$ } return agentString; } }