Clover coverage report - Ant Coverage
Coverage timestamp: Tue Apr 8 2003 20:43:55 EST
file stats: LOC: 236   Methods: 10
NCLOC: 102   Classes: 2
 
 Source file Conditionals Statements Methods TOTAL
ProcessDestroyer.java 42.9% 82.9% 80% 73.8%
 1   
 /*
 2   
  * The Apache Software License, Version 1.1
 3   
  *
 4   
  * Copyright (c) 2001-2003 The Apache Software Foundation.  All rights
 5   
  * reserved.
 6   
  *
 7   
  * Redistribution and use in source and binary forms, with or without
 8   
  * modification, are permitted provided that the following conditions
 9   
  * are met:
 10   
  *
 11   
  * 1. Redistributions of source code must retain the above copyright
 12   
  *    notice, this list of conditions and the following disclaimer.
 13   
  *
 14   
  * 2. Redistributions in binary form must reproduce the above copyright
 15   
  *    notice, this list of conditions and the following disclaimer in
 16   
  *    the documentation and/or other materials provided with the
 17   
  *    distribution.
 18   
  *
 19   
  * 3. The end-user documentation included with the redistribution, if
 20   
  *    any, must include the following acknowlegement:
 21   
  *       "This product includes software developed by the
 22   
  *        Apache Software Foundation (http://www.apache.org/)."
 23   
  *    Alternately, this acknowlegement may appear in the software itself,
 24   
  *    if and wherever such third-party acknowlegements normally appear.
 25   
  *
 26   
  * 4. The names "Ant" and "Apache Software
 27   
  *    Foundation" must not be used to endorse or promote products derived
 28   
  *    from this software without prior written permission. For written
 29   
  *    permission, please contact apache@apache.org.
 30   
  *
 31   
  * 5. Products derived from this software may not be called "Apache"
 32   
  *    nor may "Apache" appear in their names without prior written
 33   
  *    permission of the Apache Group.
 34   
  *
 35   
  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 36   
  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 37   
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 38   
  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 39   
  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 40   
  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 41   
  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 42   
  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 43   
  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 44   
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 45   
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 46   
  * SUCH DAMAGE.
 47   
  * ====================================================================
 48   
  *
 49   
  * This software consists of voluntary contributions made by many
 50   
  * individuals on behalf of the Apache Software Foundation.  For more
 51   
  * information on the Apache Software Foundation, please see
 52   
  * <http://www.apache.org/>.
 53   
  */
 54   
 
 55   
 package org.apache.tools.ant.taskdefs;
 56   
 
 57   
 import java.lang.reflect.InvocationTargetException;
 58   
 import java.lang.reflect.Method;
 59   
 import java.util.Enumeration;
 60   
 import java.util.Vector;
 61   
 
 62   
 /**
 63   
  * Destroys all registered <code>Process</code>es when the VM exits.
 64   
  *
 65   
  * @author <a href="mailto:mnewcomb@tacintel.com">Michael Newcomb</a>
 66   
  * @author <a href="mailto:jallers@advancedreality.com">Jim Allers</a>
 67   
  * @since Ant 1.5
 68   
  */
 69   
 class ProcessDestroyer
 70   
     implements Runnable {
 71   
 
 72   
     private Vector processes = new Vector();
 73   
     // methods to register and unregister shutdown hooks
 74   
     private Method addShutdownHookMethod;
 75   
     private Method removeShutdownHookMethod;
 76   
     private ProcessDestroyerImpl destroyProcessThread = null;
 77   
     
 78   
     // whether or not this ProcessDestroyer has been registered as a
 79   
     // shutdown hook
 80   
     private boolean added = false;
 81   
     
 82   
     private class ProcessDestroyerImpl extends Thread{
 83   
         private boolean shouldDestroy = true;
 84   
         
 85  30
         public ProcessDestroyerImpl(){
 86  30
             super("ProcessDestroyer Shutdown Hook");
 87   
         }
 88  30
         public void run(){
 89  30
             if(shouldDestroy){
 90  0
                 ProcessDestroyer.this.run();
 91   
             }
 92   
         }
 93   
         
 94  30
         public void setShouldDestroy(boolean shouldDestroy){
 95  30
             this.shouldDestroy = shouldDestroy;
 96   
         }
 97   
     }
 98   
     
 99   
     /**
 100   
      * Constructs a <code>ProcessDestroyer</code> and obtains 
 101   
      * <code>Runtime.addShutdownHook()</code> and 
 102   
      * <code>Runtime.removeShutdownHook()</code> through reflection. The 
 103   
      * ProcessDestroyer manages a list of processes to be destroyed when the 
 104   
      * VM exits. If a process is added when the list is empty, 
 105   
      * this <code>ProcessDestroyer</code> is registered as a shutdown hook. If 
 106   
      * removing a process results in an empty list, the
 107   
      * <code>ProcessDestroyer</code> is removed as a shutdown hook.
 108   
      */
 109  1
     public ProcessDestroyer() {
 110  1
         try {
 111   
             // check to see if the shutdown hook methods exists 
 112   
             // (support pre-JDK 1.3 VMs)
 113  1
             Class[] paramTypes = {Thread.class};
 114  1
             addShutdownHookMethod =
 115   
                 Runtime.class.getMethod("addShutdownHook", paramTypes);
 116   
             
 117  1
             removeShutdownHookMethod =
 118   
                 Runtime.class.getMethod("removeShutdownHook", paramTypes);
 119   
             // wait to add shutdown hook as needed
 120   
         } catch (Exception e) {
 121   
             // it just won't be added as a shutdown hook... :(
 122   
         }
 123   
     }
 124   
     
 125   
     /**
 126   
      * Registers this <code>ProcessDestroyer</code> as a shutdown hook, 
 127   
      * uses reflection to ensure pre-JDK 1.3 compatibility.
 128   
      */
 129  30
     private void addShutdownHook(){
 130  30
         if(addShutdownHookMethod != null){
 131  30
             destroyProcessThread = new ProcessDestroyerImpl();
 132  30
             Object[] args = {destroyProcessThread};
 133  30
             try {
 134  30
                 addShutdownHookMethod.invoke(Runtime.getRuntime(),args);
 135  30
                 added = true;
 136   
             } catch (IllegalAccessException e) {
 137   
                 // it just won't be added as a shutdown hook... :(
 138   
             } catch (InvocationTargetException e) {
 139   
                 // it just won't be added as a shutdown hook... :(
 140   
             }
 141   
         }
 142   
     }
 143   
     
 144   
     /**
 145   
      * Registers this <code>ProcessDestroyer</code> as a shutdown hook,
 146   
      * uses reflection to ensure pre-JDK 1.3 compatibility
 147   
      */
 148  30
     private void removeShutdownHook(){
 149  30
         if(removeShutdownHookMethod != null && destroyProcessThread != null){
 150  30
             Object[] args = {destroyProcessThread};
 151  30
             try{
 152  30
                 Boolean removed =
 153   
                     (Boolean) removeShutdownHookMethod.invoke(
 154   
                         Runtime.getRuntime(),
 155   
                         args);
 156  30
                 if(!removed.booleanValue()){
 157  0
                     System.err.println("Could not remove shutdown hook");
 158   
                 }
 159   
                 // start the hook thread, a unstarted thread may not be
 160   
                 // eligible for garbage collection
 161  30
                 destroyProcessThread.setShouldDestroy(false);
 162  30
                 destroyProcessThread.start();
 163   
                 // this should return quickly, since Process.destroy()
 164  30
                 try{ 
 165  30
                     destroyProcessThread.join(20000);
 166   
                 }catch(InterruptedException ie){
 167   
                     // the thread didn't die in time
 168   
                     // it should not kill any processes unexpectedly
 169   
                 }
 170  30
                 destroyProcessThread = null;
 171  30
                 added = false;
 172   
             }catch(IllegalAccessException e){
 173   
             }catch(InvocationTargetException e){
 174   
             }
 175   
         }
 176   
     }
 177   
     
 178   
     /**
 179   
      * Returns whether or not the ProcessDestroyer is registered as 
 180   
      * as shutdown hook
 181   
      * @return true if this is currently added as shutdown hook
 182   
      */
 183  0
     public boolean isAddedAsShutdownHook(){
 184  0
         return added;
 185   
     }
 186   
     
 187   
     /**
 188   
      * Returns <code>true</code> if the specified <code>Process</code> was
 189   
      * successfully added to the list of processes to destroy upon VM exit.
 190   
      * 
 191   
      * @param   process the process to add
 192   
      * @return  <code>true</code> if the specified <code>Process</code> was
 193   
      *          successfully added
 194   
      */
 195  30
     public boolean add(Process process) {
 196  30
         synchronized(processes){
 197   
             // if this list is empty, register the shutdown hook 
 198  30
             if(processes.size() == 0){
 199  30
                 addShutdownHook();
 200   
             }
 201  30
             processes.addElement(process);
 202  30
             return processes.contains(process);
 203   
         }
 204   
     }
 205   
 
 206   
     /**
 207   
      * Returns <code>true</code> if the specified <code>Process</code> was
 208   
      * successfully removed from the list of processes to destroy upon VM exit.
 209   
      *
 210   
      * @param   process the process to remove
 211   
      * @return  <code>true</code> if the specified <code>Process</code> was
 212   
      *          successfully removed
 213   
      */
 214  30
     public boolean remove(Process process) {
 215  30
         synchronized(processes){
 216  30
             boolean processRemoved = processes.removeElement(process);
 217  30
             if(processes.size() == 0){
 218  30
                 removeShutdownHook();
 219   
             }
 220  30
             return processRemoved;
 221   
         }
 222   
     }
 223   
 
 224   
     /**
 225   
      * Invoked by the VM when it is exiting.
 226   
      */
 227  0
     public void run() {
 228  0
         synchronized (processes) {
 229  0
             Enumeration e = processes.elements();
 230  0
             while (e.hasMoreElements()) {
 231  0
                 ((Process) e.nextElement()).destroy();
 232   
             }
 233   
         }
 234   
     }
 235   
 }
 236