Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.jmeter.util; import java.awt.Dimension; import java.awt.HeadlessException; import java.awt.event.ActionListener; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.lang.reflect.InvocationTargetException; import java.net.InetAddress; import java.net.URL; import java.net.UnknownHostException; import java.util.Enumeration; import java.util.Hashtable; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.MissingResourceException; import java.util.Properties; import java.util.ResourceBundle; import java.util.Vector; import java.util.concurrent.ThreadLocalRandom; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JOptionPane; import javax.swing.JTable; import javax.swing.SwingUtilities; import org.apache.commons.io.IOUtils; import org.apache.jmeter.gui.GuiPackage; import org.apache.jorphan.logging.LoggingManager; import org.apache.jorphan.reflect.ClassFinder; import org.apache.jorphan.test.UnitTestManager; import org.apache.jorphan.util.JOrphanUtils; import org.apache.log.Logger; import org.apache.oro.text.MalformedCachePatternException; import org.apache.oro.text.PatternCacheLRU; import org.apache.oro.text.regex.Pattern; import org.apache.oro.text.regex.Perl5Compiler; import org.apache.oro.text.regex.Perl5Matcher; import org.xml.sax.XMLReader; /** * This class contains the static utility methods used by JMeter. * */ public class JMeterUtils implements UnitTestManager { private static final Logger log = LoggingManager.getLoggerForClass(); // Note: cannot use a static variable here, because that would be processed before the JMeter properties // have been defined (Bug 52783) private static class LazyPatternCacheHolder { public static final PatternCacheLRU INSTANCE = new PatternCacheLRU( getPropDefault("oro.patterncache.size", 1000), // $NON-NLS-1$ new Perl5Compiler()); } private static final String EXPERT_MODE_PROPERTY = "jmeter.expertMode"; // $NON-NLS-1$ private static final String ENGLISH_LANGUAGE = Locale.ENGLISH.getLanguage(); private static volatile Properties appProperties; private static final Vector<LocaleChangeListener> localeChangeListeners = new Vector<>(); private static volatile Locale locale; private static volatile ResourceBundle resources; // What host am I running on? //@GuardedBy("this") private static String localHostIP = null; //@GuardedBy("this") private static String localHostName = null; //@GuardedBy("this") private static String localHostFullName = null; private static volatile boolean ignoreResorces = false; // Special flag for use in debugging resources private static final ThreadLocal<Perl5Matcher> localMatcher = new ThreadLocal<Perl5Matcher>() { @Override protected Perl5Matcher initialValue() { return new Perl5Matcher(); } }; /** * Gets Perl5Matcher for this thread. * @return the {@link Perl5Matcher} for this thread */ public static Perl5Matcher getMatcher() { return localMatcher.get(); } /** * This method is used by the init method to load the property file that may * even reside in the user space, or in the classpath under * org.apache.jmeter.jmeter.properties. * * The method also initialises logging and sets up the default Locale * * TODO - perhaps remove? * [still used * * @param file * the file to load * @return the Properties from the file * @see #getJMeterProperties() * @see #loadJMeterProperties(String) * @see #initLogging() * @see #initLocale() */ public static Properties getProperties(String file) { loadJMeterProperties(file); initLogging(); initLocale(); return appProperties; } /** * Initialise JMeter logging */ public static void initLogging() { LoggingManager.initializeLogging(appProperties); } /** * Initialise the JMeter Locale */ public static void initLocale() { String loc = appProperties.getProperty("language"); // $NON-NLS-1$ if (loc != null) { String[] parts = JOrphanUtils.split(loc, "_");// $NON-NLS-1$ if (parts.length == 2) { setLocale(new Locale(parts[0], parts[1])); } else { setLocale(new Locale(loc, "")); // $NON-NLS-1$ } } else { setLocale(Locale.getDefault()); } } /** * Load the JMeter properties file; if not found, then * default to "org/apache/jmeter/jmeter.properties" from the classpath * * <p> * c.f. loadProperties * * @param file Name of the file from which the JMeter properties should be loaded */ public static void loadJMeterProperties(String file) { Properties p = new Properties(System.getProperties()); InputStream is = null; try { File f = new File(file); is = new FileInputStream(f); p.load(is); } catch (IOException e) { try { is = ClassLoader.getSystemResourceAsStream("org/apache/jmeter/jmeter.properties"); // $NON-NLS-1$ if (is == null) { throw new RuntimeException("Could not read JMeter properties file:" + file); } p.load(is); } catch (IOException ex) { // JMeter.fail("Could not read internal resource. " + // "Archive is broken."); } } finally { JOrphanUtils.closeQuietly(is); } appProperties = p; } /** * This method loads a property file that may reside in the user space, or * in the classpath * * @param file * the file to load * @return the Properties from the file, may be null (e.g. file not found) */ public static Properties loadProperties(String file) { return loadProperties(file, null); } /** * This method loads a property file that may reside in the user space, or * in the classpath * * @param file * the file to load * @param defaultProps a set of default properties * @return the Properties from the file; if it could not be processed, the defaultProps are returned. */ public static Properties loadProperties(String file, Properties defaultProps) { Properties p = new Properties(defaultProps); InputStream is = null; try { File f = new File(file); is = new FileInputStream(f); p.load(is); } catch (IOException e) { try { final URL resource = JMeterUtils.class.getClassLoader().getResource(file); if (resource == null) { log.warn("Cannot find " + file); return defaultProps; } is = resource.openStream(); if (is == null) { log.warn("Cannot open " + file); return defaultProps; } p.load(is); } catch (IOException ex) { log.warn("Error reading " + file + " " + ex.toString()); return defaultProps; } } finally { JOrphanUtils.closeQuietly(is); } return p; } public static PatternCacheLRU getPatternCache() { return LazyPatternCacheHolder.INSTANCE; } /** * Get a compiled expression from the pattern cache (READ_ONLY). * * @param expression regular expression to be looked up * @return compiled pattern * * @throws MalformedCachePatternException (Runtime) * This should be caught for expressions that may vary (e.g. user input) * */ public static Pattern getPattern(String expression) throws MalformedCachePatternException { return getPattern(expression, Perl5Compiler.READ_ONLY_MASK); } /** * Get a compiled expression from the pattern cache. * * @param expression RE * @param options e.g. {@link Perl5Compiler#READ_ONLY_MASK READ_ONLY_MASK} * @return compiled pattern * * @throws MalformedCachePatternException (Runtime) * This should be caught for expressions that may vary (e.g. user input) * */ public static Pattern getPattern(String expression, int options) throws MalformedCachePatternException { return LazyPatternCacheHolder.INSTANCE.getPattern(expression, options); } @Override public void initializeProperties(String file) { System.out.println("Initializing Properties: " + file); getProperties(file); } /** * Convenience method for * {@link ClassFinder#findClassesThatExtend(String[], Class[], boolean)} * with the option to include inner classes in the search set to false * and the path list is derived from JMeterUtils.getSearchPaths(). * * @param superClass - single class to search for * @return List of Strings containing discovered class names. * @throws IOException when the used {@link ClassFinder} throws one while searching for the class */ public static List<String> findClassesThatExtend(Class<?> superClass) throws IOException { return ClassFinder.findClassesThatExtend(getSearchPaths(), new Class[] { superClass }, false); } /** * Generate a list of paths to search. * The output array always starts with * JMETER_HOME/lib/ext * and is followed by any paths obtained from the "search_paths" JMeter property. * * @return array of path strings */ public static String[] getSearchPaths() { String p = JMeterUtils.getPropDefault("search_paths", null); // $NON-NLS-1$ String[] result = new String[1]; if (p != null) { String[] paths = p.split(";"); // $NON-NLS-1$ result = new String[paths.length + 1]; System.arraycopy(paths, 0, result, 1, paths.length); } result[0] = getJMeterHome() + "/lib/ext"; // $NON-NLS-1$ return result; } /** * Provide random numbers * * @param r - * the upper bound (exclusive) * @return a random <code>int</code> */ public static int getRandomInt(int r) { return ThreadLocalRandom.current().nextInt(r); } /** * Changes the current locale: re-reads resource strings and notifies * listeners. * * @param loc - * new locale */ public static void setLocale(Locale loc) { log.info("Setting Locale to " + loc.toString()); /* * See bug 29920. getBundle() defaults to the property file for the * default Locale before it defaults to the base property file, so we * need to change the default Locale to ensure the base property file is * found. */ Locale def = null; boolean isDefault = false; // Are we the default language? if (loc.getLanguage().equals(ENGLISH_LANGUAGE)) { isDefault = true; def = Locale.getDefault(); // Don't change locale from en_GB to en if (!def.getLanguage().equals(ENGLISH_LANGUAGE)) { Locale.setDefault(Locale.ENGLISH); } else { def = null; // no need to reset Locale } } if (loc.toString().equals("ignoreResources")) { // $NON-NLS-1$ log.warn("Resource bundles will be ignored"); ignoreResorces = true; // Keep existing settings } else { ignoreResorces = false; ResourceBundle resBund = ResourceBundle.getBundle("org.apache.jmeter.resources.messages", loc); // $NON-NLS-1$ resources = resBund; locale = loc; final Locale resBundLocale = resBund.getLocale(); if (isDefault || resBundLocale.equals(loc)) {// language change worked // Check if we at least found the correct language: } else if (resBundLocale.getLanguage().equals(loc.getLanguage())) { log.info("Could not find resources for '" + loc.toString() + "', using '" + resBundLocale.toString() + "'"); } else { log.error("Could not find resources for '" + loc.toString() + "'"); } } notifyLocaleChangeListeners(); /* * Reset Locale if necessary so other locales are properly handled */ if (def != null) { Locale.setDefault(def); } } /** * Gets the current locale. * * @return current locale */ public static Locale getLocale() { return locale; } public static void addLocaleChangeListener(LocaleChangeListener listener) { localeChangeListeners.add(listener); } public static void removeLocaleChangeListener(LocaleChangeListener listener) { localeChangeListeners.remove(listener); } /** * Notify all listeners interested in locale changes. * */ private static void notifyLocaleChangeListeners() { LocaleChangeEvent event = new LocaleChangeEvent(JMeterUtils.class, locale); @SuppressWarnings("unchecked") // clone will produce correct type // TODO but why do we need to clone the list? // ANS: to avoid possible ConcurrentUpdateException when unsubscribing // Could perhaps avoid need to clone by using a modern concurrent list Vector<LocaleChangeListener> listeners = (Vector<LocaleChangeListener>) localeChangeListeners.clone(); for (LocaleChangeListener listener : listeners) { listener.localeChanged(event); } } /** * Gets the resource string for this key. * * If the resource is not found, a warning is logged * * @param key * the key in the resource file * @return the resource string if the key is found; otherwise, return * "[res_key="+key+"]" */ public static String getResString(String key) { return getResStringDefault(key, RES_KEY_PFX + key + "]"); // $NON-NLS-1$ } /** * Gets the resource string for this key in Locale. * * If the resource is not found, a warning is logged * * @param key * the key in the resource file * @param forcedLocale Force a particular locale * @return the resource string if the key is found; otherwise, return * "[res_key="+key+"]" * @since 2.7 */ public static String getResString(String key, Locale forcedLocale) { return getResStringDefault(key, RES_KEY_PFX + key + "]", // $NON-NLS-1$ forcedLocale); } public static final String RES_KEY_PFX = "[res_key="; // $NON-NLS-1$ /** * Gets the resource string for this key. * * If the resource is not found, a warning is logged * * @param key * the key in the resource file * @param defaultValue - * the default value * * @return the resource string if the key is found; otherwise, return the * default * @deprecated Only intended for use in development; use * getResString(String) normally */ @Deprecated public static String getResString(String key, String defaultValue) { return getResStringDefault(key, defaultValue); } /* * Helper method to do the actual work of fetching resources; allows * getResString(S,S) to be deprecated without affecting getResString(S); */ private static String getResStringDefault(String key, String defaultValue) { return getResStringDefault(key, defaultValue, null); } /* * Helper method to do the actual work of fetching resources; allows * getResString(S,S) to be deprecated without affecting getResString(S); */ private static String getResStringDefault(String key, String defaultValue, Locale forcedLocale) { if (key == null) { return null; } // Resource keys cannot contain spaces, and are forced to lower case String resKey = key.replace(' ', '_'); // $NON-NLS-1$ // $NON-NLS-2$ resKey = resKey.toLowerCase(java.util.Locale.ENGLISH); String resString = null; try { ResourceBundle bundle = resources; if (forcedLocale != null) { bundle = ResourceBundle.getBundle("org.apache.jmeter.resources.messages", forcedLocale); // $NON-NLS-1$ } if (bundle.containsKey(resKey)) { resString = bundle.getString(resKey); } else { log.warn("ERROR! Resource string not found: [" + resKey + "]"); resString = defaultValue; } if (ignoreResorces) { // Special mode for debugging resource handling return "[" + key + "]"; } } catch (MissingResourceException mre) { if (ignoreResorces) { // Special mode for debugging resource handling return "[?" + key + "?]"; } log.warn("ERROR! Resource string not found: [" + resKey + "]", mre); resString = defaultValue; } return resString; } /** * To get I18N label from properties file * * @param key * in messages.properties * @return I18N label without (if exists) last colon ':' and spaces */ public static String getParsedLabel(String key) { String value = JMeterUtils.getResString(key); return value.replaceFirst("(?m)\\s*?:\\s*$", ""); // $NON-NLS-1$ $NON-NLS-2$ } /** * Get the locale name as a resource. * Does not log an error if the resource does not exist. * This is needed to support additional locales, as they won't be in existing messages files. * * @param locale name * @return the locale display name as defined in the current Locale or the original string if not present */ public static String getLocaleString(String locale) { // All keys in messages.properties are lowercase (historical reasons?) String resKey = locale.toLowerCase(java.util.Locale.ENGLISH); if (resources.containsKey(resKey)) { return resources.getString(resKey); } return locale; } /** * This gets the currently defined appProperties. It can only be called * after the {@link #getProperties(String)} or {@link #loadJMeterProperties(String)} * method has been called. * * @return The JMeterProperties value, * may be null if {@link #loadJMeterProperties(String)} has not been called * @see #getProperties(String) * @see #loadJMeterProperties(String) */ public static Properties getJMeterProperties() { return appProperties; } /** * This looks for the requested image in the classpath under * org.apache.jmeter.images.<name> * * @param name * Description of Parameter * @return The Image value */ public static ImageIcon getImage(String name) { try { URL url = JMeterUtils.class.getClassLoader().getResource("org/apache/jmeter/images/" + name.trim()); if (url != null) { return new ImageIcon(url); // $NON-NLS-1$ } else { log.warn("no icon for " + name); return null; } } catch (NoClassDefFoundError | InternalError e) {// Can be returned by headless hosts log.info("no icon for " + name + " " + e.getMessage()); return null; } } /** * This looks for the requested image in the classpath under * org.apache.jmeter.images.<em><name></em>, and also sets the description * of the image, which is useful if the icon is going to be placed * on the clipboard. * * @param name * the name of the image * @param description * the description of the image * @return The Image value */ public static ImageIcon getImage(String name, String description) { ImageIcon icon = getImage(name); if (icon != null) { icon.setDescription(description); } return icon; } public static String getResourceFileAsText(String name) { BufferedReader fileReader = null; try { String lineEnd = System.getProperty("line.separator"); // $NON-NLS-1$ InputStream is = JMeterUtils.class.getClassLoader().getResourceAsStream(name); if (is != null) { fileReader = new BufferedReader(new InputStreamReader(is)); StringBuilder text = new StringBuilder(); String line; while ((line = fileReader.readLine()) != null) { text.append(line); text.append(lineEnd); } // Done by finally block: fileReader.close(); return text.toString(); } else { return ""; // $NON-NLS-1$ } } catch (IOException e) { return ""; // $NON-NLS-1$ } finally { IOUtils.closeQuietly(fileReader); } } /** * Creates the vector of Timers plugins. * * @param properties * Description of Parameter * @return The Timers value * @deprecated (3.0) not used + pre-java 1.2 collection */ @Deprecated public static Vector<Object> getTimers(Properties properties) { return instantiate(getVector(properties, "timer."), // $NON-NLS-1$ "org.apache.jmeter.timers.Timer"); // $NON-NLS-1$ } /** * Creates the vector of visualizer plugins. * * @param properties * Description of Parameter * @return The Visualizers value * @deprecated (3.0) not used + pre-java 1.2 collection */ @Deprecated public static Vector<Object> getVisualizers(Properties properties) { return instantiate(getVector(properties, "visualizer."), // $NON-NLS-1$ "org.apache.jmeter.visualizers.Visualizer"); // $NON-NLS-1$ } /** * Creates a vector of SampleController plugins. * * @param properties * The properties with information about the samplers * @return The Controllers value * @deprecated (3.0) not used + pre-java 1.2 collection */ // TODO - does not appear to be called directly @Deprecated public static Vector<Object> getControllers(Properties properties) { String name = "controller."; // $NON-NLS-1$ Vector<Object> v = new Vector<>(); Enumeration<?> names = properties.keys(); while (names.hasMoreElements()) { String prop = (String) names.nextElement(); if (prop.startsWith(name)) { Object o = instantiate(properties.getProperty(prop), "org.apache.jmeter.control.SamplerController"); // $NON-NLS-1$ v.addElement(o); } } return v; } /** * Create a string of class names for a particular SamplerController * * @param properties * The properties with info about the samples. * @param name * The name of the sampler controller. * @return The TestSamples value * @deprecated (3.0) not used */ @Deprecated public static String[] getTestSamples(Properties properties, String name) { Vector<String> vector = getVector(properties, name + ".testsample"); // $NON-NLS-1$ return vector.toArray(new String[vector.size()]); } /** * Create an instance of an org.xml.sax.Parser based on the default props. * * @return The XMLParser value * @deprecated (3.0) was only called by UserParameterXMLParser.getXMLParameters which has been removed in 3.0 */ @Deprecated public static XMLReader getXMLParser() { final String parserName = getPropDefault("xml.parser", // $NON-NLS-1$ "org.apache.xerces.parsers.SAXParser"); // $NON-NLS-1$ return (XMLReader) instantiate(parserName, "org.xml.sax.XMLReader"); // $NON-NLS-1$ } /** * Creates the vector of alias strings. * <p> * The properties will be filtered by all values starting with * <code>alias.</code>. The matching entries will be used for the new * {@link Hashtable} while the prefix <code>alias.</code> will be stripped * of the keys. * * @param properties * the input values * @return The Alias value * @deprecated (3.0) not used */ @Deprecated public static Hashtable<String, String> getAlias(Properties properties) { return getHashtable(properties, "alias."); // $NON-NLS-1$ } /** * Creates a vector of strings for all the properties that start with a * common prefix. * * @param properties * Description of Parameter * @param name * Description of Parameter * @return The Vector value */ public static Vector<String> getVector(Properties properties, String name) { Vector<String> v = new Vector<>(); Enumeration<?> names = properties.keys(); while (names.hasMoreElements()) { String prop = (String) names.nextElement(); if (prop.startsWith(name)) { v.addElement(properties.getProperty(prop)); } } return v; } /** * Creates a table of strings for all the properties that start with a * common prefix. * <p> * So if you have {@link Properties} <code>prop</code> with two entries, say * <ul> * <li>this.test</li> * <li>that.something</li> * </ul> * And would call this method with a <code>prefix</code> <em>this</em>, the * result would be a new {@link Hashtable} with one entry, which key would * be <em>test</em>. * * @param properties * input to search * @param prefix * to match against properties * @return a Hashtable where the keys are the original matching keys with * the prefix removed * @deprecated (3.0) not used */ @Deprecated public static Hashtable<String, String> getHashtable(Properties properties, String prefix) { Hashtable<String, String> t = new Hashtable<>(); Enumeration<?> names = properties.keys(); final int length = prefix.length(); while (names.hasMoreElements()) { String prop = (String) names.nextElement(); if (prop.startsWith(prefix)) { t.put(prop.substring(length), properties.getProperty(prop)); } } return t; } /** * Get a int value with default if not present. * * @param propName * the name of the property. * @param defaultVal * the default value. * @return The PropDefault value */ public static int getPropDefault(String propName, int defaultVal) { int ans; try { ans = Integer.parseInt(appProperties.getProperty(propName, Integer.toString(defaultVal)).trim()); } catch (Exception e) { log.warn("Exception '" + e.getMessage() + "' occurred when fetching int property:'" + propName + "', defaulting to:" + defaultVal); ans = defaultVal; } return ans; } /** * Get a boolean value with default if not present. * * @param propName * the name of the property. * @param defaultVal * the default value. * @return The PropDefault value */ public static boolean getPropDefault(String propName, boolean defaultVal) { boolean ans; try { String strVal = appProperties.getProperty(propName, Boolean.toString(defaultVal)).trim(); if (strVal.equalsIgnoreCase("true") || strVal.equalsIgnoreCase("t")) { // $NON-NLS-1$ // $NON-NLS-2$ ans = true; } else if (strVal.equalsIgnoreCase("false") || strVal.equalsIgnoreCase("f")) { // $NON-NLS-1$ // $NON-NLS-2$ ans = false; } else { ans = Integer.parseInt(strVal) == 1; } } catch (Exception e) { log.warn("Exception '" + e.getMessage() + "' occurred when fetching boolean property:'" + propName + "', defaulting to:" + defaultVal); ans = defaultVal; } return ans; } /** * Get a long value with default if not present. * * @param propName * the name of the property. * @param defaultVal * the default value. * @return The PropDefault value */ public static long getPropDefault(String propName, long defaultVal) { long ans; try { ans = Long.parseLong(appProperties.getProperty(propName, Long.toString(defaultVal)).trim()); } catch (Exception e) { log.warn("Exception '" + e.getMessage() + "' occurred when fetching long property:'" + propName + "', defaulting to:" + defaultVal); ans = defaultVal; } return ans; } /** * Get a String value with default if not present. * * @param propName * the name of the property. * @param defaultVal * the default value. * @return The PropDefault value */ public static String getPropDefault(String propName, String defaultVal) { String ans = defaultVal; try { String value = appProperties.getProperty(propName, defaultVal); if (value != null) { ans = value.trim(); } } catch (Exception e) { log.warn("Exception '" + e.getMessage() + "' occurred when fetching String property:'" + propName + "', defaulting to:" + defaultVal); ans = defaultVal; } return ans; } /** * Get the value of a JMeter property. * * @param propName * the name of the property. * @return the value of the JMeter property, or null if not defined */ public static String getProperty(String propName) { String ans = null; try { ans = appProperties.getProperty(propName); } catch (Exception e) { log.warn( "Exception '" + e.getMessage() + "' occurred when fetching String property:'" + propName + "'"); ans = null; } return ans; } /** * Set a String value * * @param propName * the name of the property. * @param propValue * the value of the property * @return the previous value of the property */ public static Object setProperty(String propName, String propValue) { return appProperties.setProperty(propName, propValue); } /** * Sets the selection of the JComboBox to the Object 'name' from the list in * namVec. * NOTUSED? * @param properties not used at the moment * @param combo {@link JComboBox} to work on * @param namVec List of names, which are displayed in <code>combo</code> * @param name Name, that is to be selected. It has to be in <code>namVec</code> */ @Deprecated public static void selJComboBoxItem(Properties properties, JComboBox<?> combo, Vector<?> namVec, String name) { int idx = namVec.indexOf(name); combo.setSelectedIndex(idx); // Redisplay. combo.updateUI(); } /** * Instatiate an object and guarantee its class. * * @param className * The name of the class to instantiate. * @param impls * The name of the class it must be an instance of * @return an instance of the class, or null if instantiation failed or the class did not implement/extend as required * @deprecated (3.0) not used out of this class */ // TODO probably not needed @Deprecated public static Object instantiate(String className, String impls) { if (className != null) { className = className.trim(); } if (impls != null) { impls = impls.trim(); } try { Class<?> c = Class.forName(impls); try { Class<?> o = Class.forName(className); Object res = o.newInstance(); if (c.isInstance(res)) { return res; } throw new IllegalArgumentException(className + " is not an instance of " + impls); } catch (ClassNotFoundException e) { log.error("Error loading class " + className + ": class is not found"); } catch (IllegalAccessException e) { log.error("Error loading class " + className + ": does not have access"); } catch (InstantiationException e) { log.error("Error loading class " + className + ": could not instantiate"); } catch (NoClassDefFoundError e) { log.error("Error loading class " + className + ": couldn't find class " + e.getMessage()); } } catch (ClassNotFoundException e) { log.error("Error loading class " + impls + ": was not found."); } return null; } /** * Instantiate a vector of classes * * @param v * Description of Parameter * @param className * Description of Parameter * @return Description of the Returned Value * @deprecated (3.0) not used out of this class */ @Deprecated public static Vector<Object> instantiate(Vector<String> v, String className) { Vector<Object> i = new Vector<>(); try { Class<?> c = Class.forName(className); Enumeration<String> elements = v.elements(); while (elements.hasMoreElements()) { String name = elements.nextElement(); try { Object o = Class.forName(name).newInstance(); if (c.isInstance(o)) { i.addElement(o); } } catch (ClassNotFoundException e) { log.error("Error loading class " + name + ": class is not found"); } catch (IllegalAccessException e) { log.error("Error loading class " + name + ": does not have access"); } catch (InstantiationException e) { log.error("Error loading class " + name + ": could not instantiate"); } catch (NoClassDefFoundError e) { log.error("Error loading class " + name + ": couldn't find class " + e.getMessage()); } } } catch (ClassNotFoundException e) { log.error("Error loading class " + className + ": class is not found"); } return i; } /** * Create a button with the netscape style * * @param name * Description of Parameter * @param listener * Description of Parameter * @return Description of the Returned Value * @deprecated (3.0) not used */ @Deprecated public static JButton createButton(String name, ActionListener listener) { JButton button = new JButton(getImage(name + ".on.gif")); // $NON-NLS-1$ button.setDisabledIcon(getImage(name + ".off.gif")); // $NON-NLS-1$ button.setRolloverIcon(getImage(name + ".over.gif")); // $NON-NLS-1$ button.setPressedIcon(getImage(name + ".down.gif")); // $NON-NLS-1$ button.setActionCommand(name); button.addActionListener(listener); button.setRolloverEnabled(true); button.setFocusPainted(false); button.setBorderPainted(false); button.setOpaque(false); button.setPreferredSize(new Dimension(24, 24)); return button; } /** * Create a button with the netscape style * * @param name * Description of Parameter * @param listener * Description of Parameter * @return Description of the Returned Value * @deprecated (3.0) not used */ @Deprecated public static JButton createSimpleButton(String name, ActionListener listener) { JButton button = new JButton(getImage(name + ".gif")); // $NON-NLS-1$ button.setActionCommand(name); button.addActionListener(listener); button.setFocusPainted(false); button.setBorderPainted(false); button.setOpaque(false); button.setPreferredSize(new Dimension(25, 25)); return button; } /** * Report an error through a dialog box. * Title defaults to "error_title" resource string * @param errorMsg - the error message. */ public static void reportErrorToUser(String errorMsg) { reportErrorToUser(errorMsg, JMeterUtils.getResString("error_title")); // $NON-NLS-1$ } /** * Report an error through a dialog box. * * @param errorMsg - the error message. * @param titleMsg - title string */ public static void reportErrorToUser(String errorMsg, String titleMsg) { if (errorMsg == null) { errorMsg = "Unknown error - see log file"; log.warn("Unknown error", new Throwable("errorMsg == null")); } GuiPackage instance = GuiPackage.getInstance(); if (instance == null) { System.out.println(errorMsg); return; // Done } try { JOptionPane.showMessageDialog(instance.getMainFrame(), errorMsg, titleMsg, JOptionPane.ERROR_MESSAGE); } catch (HeadlessException e) { log.warn("reportErrorToUser(\"" + errorMsg + "\") caused", e); } } /** * Finds a string in an array of strings and returns the * * @param array * Array of strings. * @param value * String to compare to array values. * @return Index of value in array, or -1 if not in array. * @deprecated (3.0) not used */ //TODO - move to JOrphanUtils? @Deprecated public static int findInArray(String[] array, String value) { int count = -1; int index = -1; if (array != null && value != null) { while (++count < array.length) { if (array[count] != null && array[count].equals(value)) { index = count; break; } } } return index; } /** * Takes an array of strings and a tokenizer character, and returns a string * of all the strings concatenated with the tokenizer string in between each * one. * * @param splittee * Array of Objects to be concatenated. * @param splitChar * Object to unsplit the strings with. * @return Array of all the tokens. */ //TODO - move to JOrphanUtils? public static String unsplit(Object[] splittee, Object splitChar) { StringBuilder retVal = new StringBuilder(); int count = -1; while (++count < splittee.length) { if (splittee[count] != null) { retVal.append(splittee[count]); } if (count + 1 < splittee.length && splittee[count + 1] != null) { retVal.append(splitChar); } } return retVal.toString(); } // End Method /** * Takes an array of strings and a tokenizer character, and returns a string * of all the strings concatenated with the tokenizer string in between each * one. * * @param splittee * Array of Objects to be concatenated. * @param splitChar * Object to unsplit the strings with. * @param def * Default value to replace null values in array. * @return Array of all the tokens. */ //TODO - move to JOrphanUtils? public static String unsplit(Object[] splittee, Object splitChar, String def) { StringBuilder retVal = new StringBuilder(); int count = -1; while (++count < splittee.length) { if (splittee[count] != null) { retVal.append(splittee[count]); } else { retVal.append(def); } if (count + 1 < splittee.length) { retVal.append(splitChar); } } return retVal.toString(); } /** * Get the JMeter home directory - does not include the trailing separator. * * @return the home directory */ public static String getJMeterHome() { return jmDir; } /** * Get the JMeter bin directory - does not include the trailing separator. * * @return the bin directory */ public static String getJMeterBinDir() { return jmBin; } public static void setJMeterHome(String home) { jmDir = home; jmBin = jmDir + File.separator + "bin"; // $NON-NLS-1$ } // TODO needs to be synch? Probably not changed after threads have started private static String jmDir; // JMeter Home directory (excludes trailing separator) private static String jmBin; // JMeter bin directory (excludes trailing separator) /** * Gets the JMeter Version. * * @return the JMeter version string */ public static String getJMeterVersion() { return JMeterVersion.getVERSION(); } /** * Gets the JMeter copyright. * * @return the JMeter copyright string */ public static String getJMeterCopyright() { return JMeterVersion.getCopyRight(); } /** * Determine whether we are in 'expert' mode. Certain features may be hidden * from user's view unless in expert mode. * * @return true iif we're in expert mode */ public static boolean isExpertMode() { return JMeterUtils.getPropDefault(EXPERT_MODE_PROPERTY, false); } /** * Find a file in the current directory or in the JMeter bin directory. * * @param fileName the name of the file to find * @return File object */ public static File findFile(String fileName) { File f = new File(fileName); if (!f.exists()) { f = new File(getJMeterBinDir(), fileName); } return f; } /** * Returns the cached result from calling * InetAddress.getLocalHost().getHostAddress() * * @return String representation of local IP address */ public static synchronized String getLocalHostIP() { if (localHostIP == null) { getLocalHostDetails(); } return localHostIP; } /** * Returns the cached result from calling * InetAddress.getLocalHost().getHostName() * * @return local host name */ public static synchronized String getLocalHostName() { if (localHostName == null) { getLocalHostDetails(); } return localHostName; } /** * Returns the cached result from calling * InetAddress.getLocalHost().getCanonicalHostName() * * @return local host name in canonical form */ public static synchronized String getLocalHostFullName() { if (localHostFullName == null) { getLocalHostDetails(); } return localHostFullName; } private static void getLocalHostDetails() { InetAddress localHost = null; try { localHost = InetAddress.getLocalHost(); } catch (UnknownHostException e1) { log.error("Unable to get local host IP address.", e1); return; // TODO - perhaps this should be a fatal error? } localHostIP = localHost.getHostAddress(); localHostName = localHost.getHostName(); localHostFullName = localHost.getCanonicalHostName(); } /** * Split line into name/value pairs and remove colon ':' * * @param headers * multi-line string headers * @return a map name/value for each header */ public static LinkedHashMap<String, String> parseHeaders(String headers) { LinkedHashMap<String, String> linkedHeaders = new LinkedHashMap<>(); String[] list = headers.split("\n"); // $NON-NLS-1$ for (String header : list) { int colon = header.indexOf(':'); // $NON-NLS-1$ if (colon <= 0) { linkedHeaders.put(header, ""); // Empty value // $NON-NLS-1$ } else { linkedHeaders.put(header.substring(0, colon).trim(), header.substring(colon + 1).trim()); } } return linkedHeaders; } /** * Run the runnable in AWT Thread if current thread is not AWT thread * otherwise runs call {@link SwingUtilities#invokeAndWait(Runnable)} * @param runnable {@link Runnable} */ public static void runSafe(Runnable runnable) { runSafe(true, runnable); } /** * Run the runnable in AWT Thread if current thread is not AWT thread * otherwise runs call {@link SwingUtilities#invokeAndWait(Runnable)} * @param synchronous flag, whether we will wait for the AWT Thread to finish its job. * @param runnable {@link Runnable} */ public static void runSafe(boolean synchronous, Runnable runnable) { if (SwingUtilities.isEventDispatchThread()) { runnable.run(); } else { if (synchronous) { try { SwingUtilities.invokeAndWait(runnable); } catch (InterruptedException e) { log.warn("Interrupted in thread " + Thread.currentThread().getName(), e); } catch (InvocationTargetException e) { throw new Error(e); } } else { SwingUtilities.invokeLater(runnable); } } } /** * Help GC by triggering GC and finalization */ public static void helpGC() { System.gc(); System.runFinalization(); } /** * Hack to make matcher clean the two internal buffers it keeps in memory which size is equivalent to * the unzipped page size * @param matcher {@link Perl5Matcher} * @param pattern Pattern */ public static void clearMatcherMemory(Perl5Matcher matcher, Pattern pattern) { try { if (pattern != null) { matcher.matches("", pattern); // $NON-NLS-1$ } } catch (Exception e) { // NOOP } } /** * Provide info, whether we run in HiDPI mode * @return {@code true} if we run in HiDPI mode, {@code false} otherwise */ public static boolean getHiDPIMode() { return JMeterUtils.getPropDefault("jmeter.hidpi.mode", false); // $NON-NLS-1$ } /** * Provide info about the HiDPI scale factor * @return the factor by which we should scale elements for HiDPI mode */ public static double getHiDPIScaleFactor() { return Double.parseDouble(JMeterUtils.getPropDefault("jmeter.hidpi.scale.factor", "1.0")); // $NON-NLS-1$ $NON-NLS-2$ } /** * Apply HiDPI mode management to {@link JTable} * @param table the {@link JTable} which should be adapted for HiDPI mode */ public static void applyHiDPI(JTable table) { if (JMeterUtils.getHiDPIMode()) { table.setRowHeight((int) Math.round(table.getRowHeight() * JMeterUtils.getHiDPIScaleFactor())); } } }