content: /* The contents of this file are subject to the terms
   * of the Common Development and Distribution License
   * (the License). You may not use this file except in
   * compliance with the License.
   *
   * You can obtain a copy of the License at
   * http://www.sun.com/cddl/cddl.html or
   * install_dir/legal/LICENSE
   * See the License for the specific language governing
   * permission and limitations under the License.
   *
   * When distributing Covered Code, include this CDDL
   * Header Notice in each file and include the License file
   * at install_dir/legal/LICENSE.
   * If applicable, add the following below the CDDL Header,
   * with the fields enclosed by brackets [] replaced by
   * your own identifying information:
   * "Portions Copyrighted [year] [name of copyright owner]"
   *
   * $Id$
   *
   * Copyright 2005-2009 Sun Microsystems Inc. All Rights Reserved
   */
  package com.sun.faban.harness.util;
  
  import com.sun.faban.common.Command;
  import com.sun.faban.common.Utilities;
  import com.sun.faban.common.CommandHandle;
  import com.sun.faban.harness.common.BenchmarkDescription;
  import com.sun.faban.harness.common.Config;
  import com.sun.faban.harness.engine.RunQ;
  import com.sun.faban.harness.formsgen.XformsGenerator;
  import com.sun.faban.harness.services.ServiceManager;
  import org.w3c.dom.Node;
  
  import javax.xml.parsers.DocumentBuilder;
  import javax.xml.parsers.DocumentBuilderFactory;
  import javax.xml.xpath.XPath;
  import javax.xml.xpath.XPathFactory;
  import java.io.File;
  import java.io.IOException;
  import java.text.SimpleDateFormat;
  import java.util.ArrayList;
  import java.util.Date;
  import java.util.Set;
  import java.util.logging.Level;
  import java.util.logging.Logger;
  
  /**
   * Benchmark deployment utility used to check/generate the deployment
   * descriptors, check proper deployment of all benchmarks or individual
   * benchmarks, and deploy them if appropriate.
   *
   * @author Akara Sucharitakul
   */
  public class DeployUtil {
  
      /** The benchmark directory. */
      public static final File BENCHMARKDIR;
  
      /** The service directory. */
      public static final File SERVICEDIR;
  
      private static Logger logger;
      static {
          logger = Logger.getLogger(DeployUtil.class.getName());
          BENCHMARKDIR = new File(Config.BENCHMARK_DIR);
          if (!BENCHMARKDIR.isDirectory()) {
              logger.severe(Config.BENCHMARK_DIR + " is not a directory");
              throw new RuntimeException(Config.BENCHMARK_DIR +
                      " is not a directory");
          }
          SERVICEDIR = new File(Config.SERVICE_DIR);
          if (!SERVICEDIR.isDirectory()) {
              logger.severe(Config.SERVICE_DIR + " is not a directory");
              throw new RuntimeException(Config.SERVICE_DIR +
                      " is not a directory");
          }
      }
  
  
      /**
       * Unjars the content a deployable jar file into the deploy directory.
       * @param jarFile The deployable jar file
       * @param deployName The name of the deployable unit
       * @throws IOException Error unjaring the jar file.
       */
      public static void unjar(File jarFile, String deployName)
              throws IOException {
                  
          logger.info("Redeploying " + deployName);
          File dir = new File(jarFile.getParent(), deployName);
  
          if (dir.exists())
              FileHelper.recursiveDelete(dir);
  
          dir.mkdir();
  
          FileHelper.unjar(jarFile.getAbsolutePath(), dir.getAbsolutePath());
      }
  
      /**
       * Processes an uploaded jar file.
       * @param jarFile The benchmark or service jar file
       * @param deployName The name of the benchmark or service
       * @throws Exception Error processing the file
       */
      public static void processUploadedJar(File jarFile, String deployName)
              throws Exception {
          unjar(jarFile, deployName);
          String jarName = jarFile.getName();
          File dir = new File(Config.BENCHMARK_DIR, deployName);
          File runXml = new File(Config.BENCHMARK_DIR + deployName +
                  File.separator + "META-INF" + File.separator + "run.xml");
          File servicesToolsXml = new File(Config.BENCHMARK_DIR + deployName +
                  File.separator + "META-INF" + File.separator +
                  "services-tools.xml");
          if (servicesToolsXml.exists() && !runXml.exists()) {
              logger.info("Redeploying Service " + deployName);
              File dir1 = new File(Config.SERVICE_DIR, deployName);
              if (dir1.exists()) {
                  FileHelper.recursiveDelete(dir1);
              }
              dir1.mkdir();
              FileHelper.copyFile(Config.BENCHMARK_DIR + jarName,
                      Config.SERVICE_DIR + jarName, false);
              FileHelper.recursiveCopy(dir, dir1);
              FileHelper.recursiveDelete(dir);
              FileHelper.recursiveDelete(new File(Config.BENCHMARK_DIR + jarName));
              /*String[] leftoverFiles = dir.list();
  
              if(leftoverFiles != null && leftoverFiles.length > 0){
                  FileHelper.recursiveDelete(dir);
              }else{
                  dir.delete();
              }*/
          } else {
              try {
                  generateDD(deployName);
                  BenchmarkDescription desc = BenchmarkDescription.
                          readDescription(deployName, dir.toString());
                  if (desc == null)
                      throw new DeployException(
                              "Missing META-INF directory in benchmark deployment.");
                  generateXform(deployName);
              } catch (Exception e) { // Clean up if we run into errors.
                  FileHelper.recursiveDelete(dir);
                  throw e;
              }
          }
      }
  
      /**
       * This method is responsible for generation the deployment descriptor.
       * @param dir The deployment directory
       */
      public static void generateDD(String dir) throws DeployException {
          String benchDir = Config.BENCHMARK_DIR + dir + File.separator;
          String metaInf = benchDir + "META-INF" + File.separator;
          String xmlPath = metaInf + "benchmark.xml";
          File benchmarkXml = new File(xmlPath);
          String configFile = null;
              try {
                  if (benchmarkXml.exists()) {
                      DocumentBuilder parser = DocumentBuilderFactory.
                              newInstance().newDocumentBuilder();
                      Node root = parser.parse(benchmarkXml).getDocumentElement();
                      XPath xPath = XPathFactory.newInstance().newXPath();
                      configFile = xPath.evaluate("config-file-name", root);
                  }
  
                  if (configFile == null || configFile.length() == 0)
                      configFile = "run.xml";
  
                  File libDir = new File(Config.LIB_DIR);
                  String[] jarFiles = libDir.list();
                  String classpath = null;
                  for (int i = 0; i < jarFiles.length; i++)
                      if (jarFiles[i].endsWith(".jar")) {
                          if (classpath == null)
                              classpath = Config.LIB_DIR + jarFiles[i];
                          else
                              classpath += File.pathSeparator + Config.LIB_DIR +
                                       jarFiles[i];
                      }
  
                  String benchLib = benchDir + "lib";
                  File benchLibDir = new File(benchLib);
                  jarFiles = benchLibDir.list();
                  if (jarFiles == null)
                      throw new IOException("Benchmark lib directory " +
                                          benchLib + " empty or non-existent");
  
                  for (int i = 0; i < jarFiles.length; i++)
                      if (jarFiles[i].endsWith(".jar"))
                          classpath += File.pathSeparator + benchLib +
                                       File.separator + jarFiles[i];
  
                  ArrayList<String> ddCmd = new ArrayList<String>();
                  ddCmd.add(Utilities.getJavaHome() + File.separator +
                                 "bin" + File.separator + "java");
                  ddCmd.add("-classpath");
                  ddCmd.add(classpath);
                  ddCmd.add("-Dbenchmark.config=" + configFile);
                  ddCmd.add("-Dbenchmark.ddfile=faban.xml");
                  ddCmd.add("com.sun.faban.driver.util.DDGenerator");
  
                  Command cmd = new Command(ddCmd);
                  cmd.setWorkingDirectory(metaInf);
                  cmd.setStreamHandling(Command.STDOUT, Command.CAPTURE);
                  cmd.setStreamHandling(Command.STDERR, Command.CAPTURE);
                  CommandHandle p = cmd.execute();
                  if (p.exitValue() != 0) {
                      StringBuilder b = new StringBuilder();
                      b.append("Error generating faban driver deployment " +
                               "descriptor for " + dir + ".\n");
  
                      byte[] output = p.fetchOutput(Command.STDOUT);
                      String o = null;
                      if (output != null)
                          o = new String(output, 0, output.length).trim();
  
                      if (o != null && o.length() > 0)
                          b.append("stdout:\n").append(o);
  
                      output = p.fetchOutput(Command.STDERR);
                      if (output != null) {
                          o = new String(output, 0, output.length).trim();
                          if (o.length() > 0)
                              b.append("\nstderr:\n").append(o);
                      }
  
                      throw new DeployException(b.toString());
                  }
              } catch (DeployException e) {
                  throw e;
              } catch (Exception e) {
                  throw new DeployException("Error generating faban driver " +
                          "descriptor for " + dir + " due to " + 
                          e.getClass().getName() + ", " + e.getMessage() + '.',
                  e);
              }
      }
  
      /**
       * This method is responsible for generating xform.
       *
       * @param dir
       * @throws java.lang.Exception
       */
      public static void generateXform(String dir) throws Exception {
          String benchDir = Config.BENCHMARK_DIR + dir + File.separator;
          XPath xPath = XPathFactory.newInstance().newXPath();
          DocumentBuilder parser = DocumentBuilderFactory.
                              newInstance().newDocumentBuilder();
          String metaInf = benchDir + "META-INF" + File.separator;
          String xmlPath = metaInf + "benchmark.xml";
          File benchmarkXml = new File(xmlPath);
          String configForm = null;
          String configFile = null;
          
          if (benchmarkXml.exists()) {
              Node root = parser.parse(benchmarkXml).getDocumentElement();
              configForm = xPath.evaluate("config-form", root);
              configFile = xPath.evaluate("config-file-name", root);
          }
  
          if (configForm == null || configForm.length() == 0) {
              configForm = "config.xhtml";
          }
  
          if (configFile == null || configFile.length() == 0){
              configFile = "run.xml";
          }
  
          File configFormFile = new File(metaInf + configForm);
          if (!configFormFile.exists()) {
              File runFile = new File(metaInf + configFile);
              if (runFile.exists()) {
                  File templateFile = new File(Config.FABAN_HOME +
                          "resources/config-template.xhtml");
                  XformsGenerator.generate(runFile, configFormFile, templateFile);
              }
          }
  
      }
  
      /**
       * Checks if benchmark can be deployed.
       * @param benchName
       * @return boolean
       */
      public static boolean canDeployBenchmark(String benchName) {
          RunQ runQ = RunQ.getHandle();
  
          if (benchName.equals(runQ.getCurrentBenchmark()))
              return false;
  
          String[][] pendingRuns = runQ.listRunQ();
          if (pendingRuns != null)
              for (int i = 0; i < pendingRuns.length; i++)
                  if (benchName.equals(pendingRuns[i][RunQ.BENCHNAME]))
                      return false;
          return true;
      }
  
      /**
       * Checks if service can be deployed.
       * @param serviceName
       * @return boolean
       */
      public static boolean canDeployService(String serviceName) {
          Set<String> activeBundles = ServiceManager.getActiveDeployments();
          String serviceBundleName = "services/" + serviceName;
          if (activeBundles != null && activeBundles.contains(serviceBundleName))
              return false;
          return true;
      }
  
      /**
       * Check for any jar files dropped in here. Deploys if needed.
       */
      public static void checkDeploy() {
          // Check for any jar files dropped in here, deploy if needed.
          File[] jarFiles = BENCHMARKDIR.listFiles();
          for (int i = 0; i < jarFiles.length; i++) {
              if (jarFiles[i].isDirectory())
                  continue;
              String suffix = ".jar";
              String jarName = jarFiles[i].getName();
              if (!jarName.endsWith(suffix))
                  continue;
              String benchName = jarName.substring(0,
                               jarName.length() - suffix.length());
              if (benchName.indexOf('.') > -1) {
                  logger.warning("Benchmark jar files must not have dots in " +
                          "the name except for \".jar\". Ignoring " + jarName +
                          ".");
                  continue;
              }
              checkDeployBenchmark(jarFiles[i], benchName);
          }
  
          File[] jarFiles1 = SERVICEDIR.listFiles();
          for (int i = 0; i < jarFiles1.length; i++) {
              if (jarFiles1[i].isDirectory())
                  continue;
              String suffix = ".jar";
              String jarName = jarFiles1[i].getName();
              if (!jarName.endsWith(suffix))
                  continue;
              String serviceName = jarName.substring(0,
                               jarName.length() - suffix.length());
              if (serviceName.indexOf('.') > -1) {
                  logger.warning("Service jar files must not have dots in " +
                          "the name except for \".jar\". Ignoring " + jarName +
                          ".");
                  continue;
              }
  
              checkDeployService(jarFiles1[i], serviceName);
          }
  
      }
  
      /**
       * Checks for service deployment.
       * @param jarFile The service jar file
       * @param serviceName The service name
       */
      public static void checkDeployService(File jarFile, String serviceName) {
          File serviceDir = new File(SERVICEDIR, serviceName);
          if (serviceDir.isDirectory()) {
              if (jarFile.lastModified() > serviceDir.lastModified())
                  deployService(jarFile, serviceName);
          } else {
              deployService(jarFile, serviceName);
          }
      }
  
      /**
       * Checks for benchmark deployment.
       * @param jarFile The benchmark jar file
       * @param benchName The benchmark name
       */
      public static void checkDeployBenchmark(File jarFile, String benchName) {
          File benchDir = new File(BENCHMARKDIR, benchName);
          if (benchDir.isDirectory()) {
              if (jarFile.lastModified() > benchDir.lastModified())
                  deployBenchmark(jarFile, benchName);
          } else {
              deployBenchmark(jarFile, benchName);
          }
      }
  
      /**
       * Deploys a benchmark.
       * @param jarFile The benchmark jar file
       * @param benchName The benchmark name
       */
      public static void deployBenchmark(File jarFile, String benchName) {
          if (canDeployBenchmark(benchName))
              try {
                  unjar(jarFile, benchName);
                  generateDD(benchName);
                  generateXform(benchName);
              } catch (Exception e) {
                  logger.log(Level.SEVERE, "Error deploying benchmark \"" +
                          benchName + "\"", e);
                  File dir = new File(Config.BENCHMARK_DIR, benchName);
                  if (dir.exists())
                      FileHelper.recursiveDelete(dir);
              }
      }
  
      /**
       * Deploys a service.
       * @param jarFile The service jar file
       * @param serviceBundleName The service bundle name
       */
      public static void deployService(File jarFile, String serviceBundleName) {
          if (canDeployService(serviceBundleName))
              try {
                  unjar(jarFile, serviceBundleName);
              } catch (Exception e) {
                  logger.log(Level.SEVERE, "Error deploying service bundle \"" +
                          serviceBundleName + "\"", e);
                  File dir = new File(Config.SERVICE_DIR, serviceBundleName);
                  if (dir.exists())
                      FileHelper.recursiveDelete(dir);
              }
      }
  
      /**
       * Clears benchmark's configuration.
       * @param benchName The banchmark name
       */
      public static void clearConfig(String benchName) {
  
          // 1. Figure out the config file name.
          BenchmarkDescription benchDesc = BenchmarkDescription.
                  getDescription(benchName);
          if (benchDesc == null)
              return;
          
          String configFileName = benchDesc.configFileName + '.' + benchName;
  
          // 2. Go to the config/profiles directory and rename all config
          // files underneath.
          File[] profiles = new File(Config.PROFILES_DIR).listFiles();
          if (profiles != null && profiles.length > 0) {
              String date = null;
              for (File profile : profiles) {
                  File configFile = new File(profile, configFileName);
                  if (configFile.exists()) {
                      if (date == null) {
                          SimpleDateFormat format =
                                  new SimpleDateFormat("yyMMddHHmmss");
                          date = "." + format.format(new Date());
                      }
                      File newName = new File(profile, configFileName + date);
                      configFile.renameTo(newName);
                  } else if (profile.isFile() &&
                             configFileName.equals(profile.getName())) {
                      if (date == null) {
                          SimpleDateFormat format =
                                  new SimpleDateFormat("yyMMddHHmmss");
                          date = "." + format.format(new Date());
                      }
                      File newName = new File(Config.PROFILES_DIR,
                                                  configFileName + date);
                      profile.renameTo(newName);
                  }
              }
          }
      }
  }
  