Package com.sun.jini.qa.harness

Source Code of com.sun.jini.qa.harness.ActivationSystemAdmin$ActSysAnnotator

/*
* 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 com.sun.jini.qa.harness;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.rmi.RemoteException;
import java.rmi.activation.ActivationGroup;
import java.rmi.activation.ActivationException;
import java.rmi.activation.ActivationSystem;
import java.rmi.Naming;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* A implementation of <code>Admin</code> which manages
* the activation system.
* This admin implementation defines the following well-known tokens:
* <table>
* <tr><td> <code>logdir</code>     
* <td>                 the directory path to use for the activation systems
*                      log files. If specified, this path must be a valid
*                      absolute or relative path name, and is used directly
*                      as obtained from the configuration object. If
*                      this parameter is not specified, a temporary directory
*                      is created. In all cases, this directory and it's
*                      contents are deleted by the <code>stop</code> method.
* <tr><td> <code>type</code>
* <td>                 a mandatory token identifying the type of activation
*                      system being used. Valid values are one of the strings
*                      <code>"rmid"</code> or <code>"phoenix"</code>.
* <tr><td> <code>classpath</code>
* <td>                 if <code>type</code> is <code>"phoenix"</code>, then
*                      this token must be defined and have the value of the
*                      classpath for phoenix, which is assumed to be a single
*                      executable .jar file.
* <tr><td> <code>policyfile</code>
* <td>                 if <code>type</code> is <code>"phoenix"</code>, then
*                      this token must be defined and specify the location
*                      of the security policy file for the activation system.
* <tr>td> <code>serviceTemplate</code>
* <td>                 if <code>type</code> is <code>"phoenix"</code>, then
*                      this token must be defined and specify the
*                      Configuration file relative to the root of the
*                      configuration tree.
* </table>
* Additional supported tokens include <code>serverjvmopts</code> and
* <code>serverjvmprops</code>
* The proxy returned by <code>getProxy</code> is the remote reference
* to the <code>ActivationSystem.</code>
* <p>
* The configuration value named by the key
* <code>com.sun.jini.qa.harness.actdeathdelay</code> specifies a time delay
* to be injected between the time <code>stop</code> is called and the
* activation system is actually killed. This is done to give services
* which may have initiated a shutdown time to complete termination
* processing. If undefined, a default of 5 seconds is used.
* <p>
* The logger named <code>com.sun.jini.qa.harness.service</code> is used
* to log debug information
*
* <table border=1 cellpadding=5>
*
*<tr> <th> Level <th> Description
*
*<tr> <td> FINE <td> the command line used to start the activation system
*</table>
*/
public class ActivationSystemAdmin
                           extends AbstractServiceAdmin
                           implements Admin
{

    private static Logger logger =
  Logger.getLogger("com.sun.jini.qa.harness");

    /** flag indicated the act system was started by this class */
    private static boolean started = false;

    /** the service proxy */
    private ActivationSystem actSystem;

    /** the activation system process */
    private Process actProcess;

    /** the activation system log directory */
    private String logDirName;

    /** the stdout pipe */
    private Pipe outPipe;

    /** the stderr pipe */
    private Pipe errPipe;

    /**
     * Return an indication of whether the activation has already been
     * started by an instance of this admin in this VM.
     *
     * @return true of the activation system has been started
     */
    public static boolean wasStarted() {
  return started;
    }

    /**
     * Construct an instance of <code>ActivationSystemAdmin</code>.
     *
     * @param config         the configuration object for this test run
     *
     * @param serviceName  the prefix used to build the property
     *                       names needed to acquire service parameters
     *
     * @param index       the instance number for this service.
     */
    public ActivationSystemAdmin(QAConfig config,
               String serviceName,
               int index)
    {
  super(config, serviceName, index);
    }

    /**
     * Starts the activation system. This method first checks whether
     * the activation system is already running. If so, a
     * <code>TestException</code> is thrown. If the test property
     * <code>com.sun.jini.qa.harness.runactivation</code> is defined and
     * has the value <code>false</code> this method returns without
     * starting the activation system. Otherwise, this method
     * check whether a running activation system can be detected (presumably
     * resulting from a cleanup problem from a previous test) and
     * attempt to shut it down if so. Then this method
     * constructs a command line for executing the activation system.
     * If the activation system is phoenix, any configuration overrides
     * provided by registered <code>OverrideProvider</code>s are included
     * on the command line. Since this admin execs a process, it may be
     * necessary for these overrides to escape special characters
     * interpreted by the underlying OS.
     * <p>
     * The value of the system property <code>type</code> controls the content
     * and structure of the generated command line. This method then
     * starts the activation system by executing the generated command line
     * after which the <code>ActivationSystem</code> reference is obtained
     * for use by the <code>stop</code> and <code>getProxy</code> methods.
     * If the reference cannot be obtained within 10 seconds, a
     * <code>TestException</code> is thrown.
     *
     * @throws TestException    if the activation system has already been
     *                          started by an instance of this admin,
     *                          if the <code>actCommand</code> parameter is not
     *                          found, if the activation system is already
     *                          running, if starting the activation system
     *                          fails, if the configuration file for
     *                          the activation system is undefined, or if
     *                          the type property does not have a proper value.
     *
     * @throws RemoteException  never.
     */
    public void start() throws RemoteException, TestException {
  if (started) {
      throw new TestException("ActivationSystemAdmin: an activation "
          + "system has "
          + "already been started by this class");
  }
  if (!config.getBooleanConfigVal("com.sun.jini.qa.harness.runactivation",
                true))
  {
      logger.log(Level.FINE, "Activation system is disabled");
      return;
  } else {
      cleanupRunningActivationSystem(); // clean up a lingering old one
  }
  String type = getServiceType();
  if (! (type.equals("rmid") || type.equals("phoenix"))) {  
      throw new TestException("'type' for " + serviceName
            + " is " + type + " - must be "
            + " either 'rmid' or 'phoenix'");
  }

  ArrayList l = new ArrayList(10);
  String actCommand = null;
  if (type.equals("rmid")) {
      l.add(System.getProperty("java.home") + "/bin/rmid");
  } else {
      l.add(System.getProperty("java.home") + "/bin/java");
  }
  l.add("-Djava.security.policy=" + getServicePolicyFile());
  String[] opts = getServiceOptions();
  if (opts != null) {
      for (int i = 0; i < opts.length; i++) {
    l.add(opts[i]);
      }
  }
  String[] props = getServiceProperties();
  if (props != null) {
      for (int i = 0; i < props.length; i += 2) {
    l.add("-D" + props[i] + "=" + props[i+1]);
      }
  }
  // don't use -jar syntax in case of augmented classpath
  if (type.equals("phoenix")) {
      l.add("-Djava.rmi.server.codebase=" + getServiceCodebase());
      l.add("-cp");
      l.add(getServiceClasspath());
      l.add("com.sun.jini.phoenix.Activation");
      l.add(getServiceConfigurationFileName());
  }

  logDirName = getServicePersistenceLog();
  if (logDirName != null) {
      if (type.equals("rmid")) {
    l.add("-log");
    l.add(logDirName);
      } else { // unicode '"' to work around windows platform issue
    l.add("com.sun.jini.phoenix.persistenceDirectory="
          + "\\u0022" + logDirName + "\\u0022");
    addRegisteredOverrides(l);
      }
  }
  String[] cmdArray = (String[]) l.toArray(new String[0]);
  StringBuffer cmdBuf = new StringBuffer();
  for (int i = 0; i < cmdArray.length; i++) {
      if (i != 0) {
    cmdBuf.append(" ");
      }
      cmdBuf.append(cmdArray[i]);
  }
  logger.log(Level.FINE, "command: '" + cmdBuf + "'");
  getServicePreparerName();
  logServiceParameters();
  try {
      actProcess = Runtime.getRuntime().exec(cmdArray);
      outPipe = new Pipe("activation system-out",
             actProcess.getInputStream(),
             System.out,
             null,
             new ActSysAnnotator("ActSys-out: "));
      errPipe = new Pipe("activation system-err",
             actProcess.getErrorStream(),
             System.out,
             null,
             new ActSysAnnotator("ActSys-err: "));
  } catch (IOException e) {
      throw new TestException("ActivationSystemAdmin: Failed to exec "
          + "the activation system", e);
  }
  if (!config.activationUp(60)) {
      throw new TestException("ActivationSystemAdmin: activation system "
            + "did not start");
  }
  try {
      actSystem = ActivationGroup.getSystem();
  } catch (ActivationException e) {
      try {
    int exitStatus = actProcess.exitValue();
    throw new TestException("ActivationSystemAdmin: activation "
          + "system exited with status "
          + exitStatus, e);
      } catch (IllegalThreadStateException ignore) {
    throw new TestException("ActivationSystemAdmin: problem "
          + "getting activation system",
          e);
      }
  }
  ActivationSystemAdmin.started = true;
  actSystem = (ActivationSystem) doProxyPreparation(actSystem);
    }

    /**
     * Annotator for annotating output merged into test log
     */
    private class ActSysAnnotator implements Pipe.Annotator {

  private String annotation;

        ActSysAnnotator(String annotation) {
      this.annotation = annotation;
  }

  public String getAnnotation() {
      return annotation;
  }
    }

    /**
     * Stop the activation system. This method stops the activation system
     * by calling <code>ActivationSystem.shutdown</code>. A
     * <code>RemoteException</code> is thrown if the shutdown fails.
     * <p>
     * If the test property
     * <code>com.sun.jini.qa.harness.actdeathdelay</code> exists and is
     * greater than 0, the value is interpreted as the number of seconds
     * to sleep before shutting down the activation system. If it exists
     * and is non-positive, no delay is imposed. If the value does not
     * exist, a default value of 5 seconds is assumed.
     *
     * @throws RemoteException if failed to contact/shutdown the activation
     *                         system
     */
    public void stop() throws RemoteException {
  if (actSystem == null) {
      return;
  }
  int delay =
      config.getIntConfigVal("com.sun.jini.qa.harness.actdeathdelay", 5);
  if (delay > 0) {
      logger.log(Level.FINEST,
           "activation death delayed " + delay + " seconds");
      try {
    Thread.sleep(delay * 1000);
      } catch (InterruptedException ignore) {
      }
  }
  actSystem.shutdown();
  outPipe.waitTillEmpty(5000); //give pipes up to 5 seconds to drain
  errPipe.waitTillEmpty(5000);
  actSystem = null;
  actProcess = null;
  cleanupLogs();
    }

    /**
     * Clean up the activation system log directory. First, all files
     * in <code>logDir</code> are deleted, after which <code>logDir</code>
     * itself is deleted. Each deletion call is attempted up to 10 times, with
     * a 500ms delay between calls. This is done to work around cases where
     * the log files may be held by the activation system process, which may
     * still be active at the time this method is entered.
     */
    private void cleanupLogs() {
  if (logDirName == null) {
      logger.log(Level.FINE, "Persistence directory is undefined");
      return;
  }
  File logDir = new File(logDirName);
  File[] files = logDir.listFiles();
  if (files != null) {
      if (files.length == 0) {
    logger.log(Level.FINEST,
         "log directory " + logDir + " is empty");
      }
      for (int i = 0; i < files.length; i++) {
    boolean success = false;
    for (int counter = 10; counter >= 0; --counter) {
        success = files[i].delete();
        if (success) {
      break;
        } else {
      try {
          Thread.sleep(500);
      } catch (InterruptedException ignore) {
      }
        }
    }
    if (success) {
        logger.log(Level.FINEST,
             "successfully deleted activation log file "
             + files[i]);
    } else {
        logger.log(Level.FINEST,
             "failed to delete activation log file "
             + files[i]);
    }
      }
  } else {
      logger.log(Level.FINEST,
           "could not obtain list for log directory "
           + logDir);
  }
  if (logDir.delete()) {
      logger.log(Level.FINEST,
           "successfully deleted activation log directory "
           + logDir);
  } else {
      logger.log(Level.FINEST,
           "failed to delete activation log directory "
           + logDir);
  }
    }

    /**
     * Return the <code>ActivationSystem</code> reference for the activation
     * system managed by this admin.
     *
     * @return the <code>ActivationSystem</code> proxy
     */
    public Object getProxy() {
  return actSystem;
    }

    /**
     * Destroy a running activation system. Intended for cleanup when a test
     * expects to start it's own activation system. It is important to call this
     * method before any other use of the activation system. Specifically if
     * <code>ActivationGroup.getSystem</code> has already been called in this
     * VM, then the remote reference to the activation system will have been
     * cached. If this method is called, then that cached reference will no
     * longer be valid and future attempts to contact the activation system will
     * fail (in this VM).
     */
    private void cleanupRunningActivationSystem() {
  int port;
  ActivationSystem currSystem = null;
  String actURL = null;
  try {
      port = Integer.getInteger("java.rmi.activation.port",
              ActivationSystem.SYSTEM_PORT).intValue();
      actURL = "//:" + port + "/java.rmi.activation.ActivationSystem";
      currSystem = (ActivationSystem) Naming.lookup(actURL);
      currSystem.shutdown();
  } catch (SecurityException e) {
      throw e; // configuration problem
  } catch (Exception e) {
      return; // assume not be running
  }
  logger.log(Level.FINE, "Activation System detected - terminating");
  int delay =
      config.getIntConfigVal("com.sun.jini.qa.harness.actdeathdelay", 5);
  try {
      for (int i = 0; i < delay; i++) {
    Thread.sleep(1000);
    Naming.lookup(actURL);
      }
      logger.log(Level.SEVERE, "Failed to destroy activation system");
  } catch (Exception lookupGone) {
  }
    }
}
TOP

Related Classes of com.sun.jini.qa.harness.ActivationSystemAdmin$ActSysAnnotator

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.