Package net.grinder.engine.agent

Source Code of net.grinder.engine.agent.PropertyBuilder

/*
* 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.util.Directory;
import net.grinder.util.NetworkUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.hyperic.sigar.Sigar;
import org.hyperic.sigar.SigarException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FilenameFilter;
import java.net.InetAddress;
import java.util.List;

import static org.ngrinder.common.util.Preconditions.checkNotEmpty;
import static org.ngrinder.common.util.Preconditions.checkNotNull;

/**
* Class which is responsible to build custom jvm arguments.
* <p/>
* This class aware of security. So it produces the appropriate JVM arguments
* which works at security env.
*
* @author JunHo Yoon
* @since 3.0
*/
public class PropertyBuilder {
  private static final Logger LOGGER = LoggerFactory.getLogger(ProcessBuilder.class);
  private final GrinderProperties properties;
  private final Directory baseDirectory;
  private final String hostName;
  private final boolean securityEnabled;
  private final String hostString;
  private final boolean server;
  private final boolean useXmxLimit;
  private final String additionalJavaOpt;
  private boolean enableLocalDNS;


  /**
   * Constructor with null additional java opt value.
   *
   * @param properties        {@link GrinderProperties}
   * @param baseDirectory     base directory which the script executes.
   * @param securityEnabled   true if security enable mode
   * @param hostString        hostString
   * @param hostName          current host name
   * @param server            server mode
   * @param useXmxLimit       true if 1G limit should be enabled
   * @param enableLocalDNS    true if the local dns should be enabled.
   * @param additionalJavaOpt additional java option to be provided when invoking agent
   *                          process
   */
  public PropertyBuilder(GrinderProperties properties, Directory baseDirectory, boolean securityEnabled,
               String hostString, String hostName, boolean server, boolean useXmxLimit, boolean enableLocalDNS, String additionalJavaOpt) {
    this.enableLocalDNS = enableLocalDNS;
    this.properties = checkNotNull(properties);
    this.baseDirectory = checkNotNull(baseDirectory);
    this.securityEnabled = securityEnabled;
    this.hostString = hostString;
    this.hostName = checkNotEmpty(hostName);
    this.server = server;
    this.useXmxLimit = useXmxLimit;
    this.additionalJavaOpt = additionalJavaOpt;
  }

  /**
   * Constructor with null additional java opt value.
   *
   * @param properties        {@link GrinderProperties}
   * @param baseDirectory     base directory which the script executes.
   * @param securityEnabled   true if security enable mode
   * @param hostString        hostString
   * @param hostName          current host name
   * @param server            server mode
   * @param useXmxLimit       true if 1G limit should be enabled
   * @param additionalJavaOpt additional java option to be provided when invoking agent
   *                          process
   */
  public PropertyBuilder(GrinderProperties properties, Directory baseDirectory, boolean securityEnabled,
               String hostString, String hostName, boolean server, boolean useXmxLimit, String additionalJavaOpt) {
    this(properties, baseDirectory, securityEnabled, hostString, hostName, server, useXmxLimit, true, additionalJavaOpt);
  }

  /**
   * Constructor with null additional java opt value.
   *
   * @param properties      {@link GrinderProperties}
   * @param baseDirectory   base directory which the script executes.
   * @param securityEnabled true if security enable mode
   * @param hostString      hostString
   * @param hostName        current host name
   * @param server          server mode
   * @param useXmxLimit     true if 1G limit should be enabled
   */
  public PropertyBuilder(GrinderProperties properties, Directory baseDirectory, boolean securityEnabled,
               String hostString, String hostName, boolean server, boolean useXmxLimit) {
    this(properties, baseDirectory, securityEnabled, hostString, hostName, server, useXmxLimit, null);
  }

  /**
   * Constructor.
   *
   * @param properties      {@link GrinderProperties}
   * @param baseDirectory   base directory which the script executes.
   * @param securityEnabled true if security enable mode
   * @param hostString      hostString
   * @param hostName        current host name
   * @param server          server mode
   */
  public PropertyBuilder(GrinderProperties properties, Directory baseDirectory, boolean securityEnabled,
               String hostString, String hostName, boolean server) {
    this(properties, baseDirectory, securityEnabled, hostString, hostName, server, true);
  }

  /**
   * Constructor.
   *
   * @param properties      {@link GrinderProperties}
   * @param baseDirectory   base directory which the script executes.
   * @param securityEnabled true if security enable mode
   * @param hostString      hostString
   * @param hostName        current host name
   */
  public PropertyBuilder(GrinderProperties properties, Directory baseDirectory, boolean securityEnabled,
               String hostString, String hostName) {
    this(properties, baseDirectory, securityEnabled, hostString, hostName, false);
  }

  /**
   * Build JVM Arguments.
   *
   * @return generated jvm arguments
   */
  public String buildJVMArgument() {
    return addMemorySettings(new StringBuilder(buildJVMArgumentWithoutMemory())).toString();
  }

  /**
   * Build JVM Arguments.
   *
   * @return generated jvm arguments
   */
  public String buildJVMArgumentWithoutMemory() {
    StringBuilder jvmArguments = new StringBuilder();
    if (securityEnabled) {
      jvmArguments = addSecurityManager(jvmArguments);
      jvmArguments = addCurrentAgentPath(jvmArguments);
      jvmArguments = addConsoleIP(jvmArguments);
      jvmArguments = addDnsIP(jvmArguments);
    } else {
      jvmArguments.append(properties.getProperty("grinder.jvm.arguments", ""));
      jvmArguments = addNativeLibraryPath(jvmArguments);
    }
    jvmArguments = addParam(jvmArguments, properties.getProperty("grinder.param", ""));
    jvmArguments = addPythonPathJvmArgument(jvmArguments);
    jvmArguments = addCustomDns(jvmArguments);
    if (server) {
      jvmArguments = addServerMode(jvmArguments);
    }
    if (StringUtils.isNotBlank(additionalJavaOpt)) {
      jvmArguments = addAdditionalJavaOpt(jvmArguments);
    }
    return jvmArguments.toString();
  }

  private StringBuilder addParam(StringBuilder jvmArguments, String param) {
    if (StringUtils.isEmpty(param)) {
      return jvmArguments;
    }
    return jvmArguments.append(" -Dparam=").append(param).append(" ");
  }

  private StringBuilder addAdditionalJavaOpt(StringBuilder jvmArguments) {
    return jvmArguments.append(" ").append(additionalJavaOpt).append(" ");
  }

  private StringBuilder addNativeLibraryPath(StringBuilder jvmArguments) {
    return jvmArguments.append(" -Djna.library.path=").append(new File(baseDirectory.getFile(), "/lib"))
        .append(" ");
  }

  protected static final long MIN_PER_PROCESS_MEM_SIZE = 50 * 1024 * 1024;
  protected static final long DEFAULT_XMX_SIZE = 500 * 1024 * 1024;
  protected static final long DEFAULT_MAX_XMX_SIZE = 1024 * 1024 * 1024;

  protected StringBuilder addMemorySettings(StringBuilder jvmArguments) {
    String processCountStr = properties.getProperty("grinder.processes", "1");
    // For compatibility, try both.
    int reservedMemoryUnit = properties.getInt("grinder.reserved.memory", 0);
    if (reservedMemoryUnit == 0) {
      reservedMemoryUnit = properties.getInt("grinder.memory.reserved", 300);
    }

    int reservedMemory = Math.max(reservedMemoryUnit, 0) * 1024 * 1024;
    int processCount = NumberUtils.toInt(processCountStr, 1);
    long desirableXmx; // make 500M as default.
    long permGen = 32 * 1024 * 1024;
    try {
      // Make a free memory room size of reservedMemory.
      long free = new Sigar().getMem().getActualFree() - reservedMemory;
      long perProcessTotalMemory = Math.max(free / processCount, MIN_PER_PROCESS_MEM_SIZE);
      desirableXmx = (long) (perProcessTotalMemory * 0.5);
      permGen = Math.min(Math.max((long) (perProcessTotalMemory * 0.2), 50L * 1024 * 1024), 128 * 1024 * 1024);
      if (this.useXmxLimit) {
        desirableXmx = Math.min(DEFAULT_MAX_XMX_SIZE, desirableXmx);
      }
    } catch (UnsatisfiedLinkError e) {
      LOGGER.error("Sigar lib link error: {}", e.getMessage());
      desirableXmx = DEFAULT_XMX_SIZE;
    } catch (SigarException e) {
      LOGGER.error("Error occurred while calculating memory size : {}", e.getMessage());
      desirableXmx = DEFAULT_XMX_SIZE;
    }

    jvmArguments.append(" -Xms").append(getMemorySize(desirableXmx)).append("m -Xmx").append(getMemorySize(desirableXmx)).append("m ");
    jvmArguments.append(" -XX:PermSize=")
        .append(properties.getInt("grinder.memory.permsize", getMemorySize(permGen))).append("m ");
    jvmArguments.append(" -XX:MaxPermSize=")
        .append(properties.getInt("grinder.memory.maxpermsize", getMemorySize(permGen))).append("m ");
    return jvmArguments;
  }

  private int getMemorySize(long memoryInByte) {
    return (int) (memoryInByte / (1024 * 1024));
  }

  protected StringBuilder addServerMode(StringBuilder jvmArguments) {
    return jvmArguments.append(" -server ");
  }

  protected StringBuilder addSecurityManager(StringBuilder jvmArguments) {
    return jvmArguments.append(" -Djava.security.manager=org.ngrinder.sm.NGrinderSecurityManager ");
  }

  private String getPath(File file, boolean useAbsolutePath) {
    return useAbsolutePath ? FilenameUtils.normalize(file.getAbsolutePath()) : file.getPath();
  }

  /**
   * Build custom class path based on the jar files on given base path.
   *
   * @param useAbsolutePath true if the class path entries should be represented as
   *                        absolute path
   * @return classpath string
   */
  @SuppressWarnings("ResultOfMethodCallIgnored")
  public String buildCustomClassPath(final boolean useAbsolutePath) {
    File baseFile = baseDirectory.getFile();
    File libFolder = new File(baseFile, "lib");
    final StringBuffer customClassPath = new StringBuffer();
    customClassPath.append(getPath(baseFile, useAbsolutePath));
    if (libFolder.exists()) {
      customClassPath.append(File.pathSeparator).append(getPath(new File(baseFile, "lib"), useAbsolutePath));
      libFolder.list(new FilenameFilter() {
        @Override
        public boolean accept(File dir, String name) {
          if (name.endsWith(".jar")) {
            customClassPath.append(File.pathSeparator)
                .append(getPath(new File(dir, name), useAbsolutePath));
          }
          return true;
        }
      });
    }
    return customClassPath.toString();
  }

  /**
   * Rebase class path from relative path to absolute path.
   *
   * @param classPath class path
   * @return converted path.
   */
  public String rebaseCustomClassPath(String classPath) {
    StringBuilder newClassPath = new StringBuilder();
    boolean isFirst = true;
    for (String each : StringUtils.split(classPath, ";:")) {
      File file = new File(baseDirectory.getFile(), each);
      if (!isFirst) {
        newClassPath.append(File.pathSeparator);
      }
      isFirst = false;
      newClassPath.append(FilenameUtils.normalize(file.getAbsolutePath()));
    }
    return newClassPath.toString();
  }

  @SuppressWarnings("ResultOfMethodCallIgnored")
  private StringBuilder addPythonPathJvmArgument(StringBuilder jvmArguments) {
    jvmArguments.append(" -Dpython.path=");
    jvmArguments.append(new File(baseDirectory.getFile(), "lib").getAbsolutePath());
    String pythonPath = System.getenv().get("PYTHONPATH");
    if (pythonPath != null) {
      jvmArguments.append(File.pathSeparator).append(pythonPath);
    }
    String pythonHome = System.getenv().get("PYTHONHOME");
    if (pythonHome != null) {
      jvmArguments.append(" -Dpython.home=");
      jvmArguments.append(pythonHome);
    }
    jvmArguments.append(" ");
    File jythonCache = new File(FileUtils.getTempDirectory(), "jython");
    jythonCache.mkdirs();
    jvmArguments.append(" -Dpython.cachedir=").append(jythonCache.getAbsolutePath()).append(" ");
    return jvmArguments;
  }

  private StringBuilder addCurrentAgentPath(StringBuilder jvmArguments) {
    return jvmArguments.append(" -Dngrinder.exec.path=").append(baseDirectory.getFile()).append(" ");
  }

  private StringBuilder addConsoleIP(StringBuilder jvmArguments) {
    return jvmArguments.append(" -Dngrinder.console.ip=")
        .append(properties.getProperty(GrinderProperties.CONSOLE_HOST, "127.0.0.1")).append(" ");
  }

  StringBuilder addDnsIP(StringBuilder jvmArguments) {
    try {
      List<?> dnsServers = NetworkUtils.getDnsServers();
      if (!dnsServers.isEmpty()) {
        return jvmArguments.append(" -Dngrinder.dns.ip=").append(StringUtils.join(dnsServers, ",")).append(" ");
      }
    } catch (Exception e) {
      LOGGER.error("Error while adding DNS IPs for the security mode. This might be occurred by not using " +
          "Oracle JDK : {}", e.getMessage());
    }
    return jvmArguments;
  }

  private StringBuilder addCustomDns(StringBuilder jvmArguments) {
    jvmArguments.append(" -Dngrinder.etc.hosts=").append(hostName).append(":127.0.0.1,localhost:127.0.0.1");
    if (StringUtils.isNotEmpty(hostString)) {
      jvmArguments.append(",").append(rebaseHostString(hostString));
    }
    if (enableLocalDNS) {
      jvmArguments.append(" -Dsun.net.spi.nameservice.provider.1=dns,LocalManagedDns ");
    }
    return jvmArguments;
  }

  /**
   * Rebase Host String.. add the missing ip addresses if only host is
   * provided..
   *
   * @param hostString host string
   * @return completed host string.
   */
  public String rebaseHostString(String hostString) {
    String[] split = StringUtils.split(hostString, ",");
    StringBuilder newHostString = new StringBuilder();
    boolean first = true;
    for (String pair : split) {
      if (!first) {
        newHostString.append(",");
      }
      first = false;
      if (pair.startsWith(":")) {
        newHostString.append(pair);
      } else if (pair.contains(":")) {
        newHostString.append(pair);
      } else if (securityEnabled) {
        // When the security mode is enabled, we should provide all IPs
        boolean eachFirst = true;
        for (InetAddress each : NetworkUtils.getIpsFromHost(pair)) {
          if (!eachFirst) {
            newHostString.append(",");
          }
          newHostString.append(pair).append(":").append(each.getHostAddress());
          eachFirst = false;
        }
      }
    }
    return newHostString.toString();
  }

  void addProperties(String key, String value) {
    this.properties.put(key, value);
  }
}
TOP

Related Classes of net.grinder.engine.agent.PropertyBuilder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.