Home » apache-ant-1.7.1-src » org.apache.tools » ant » taskdefs » [javadoc | source]
    1   /*
    2    *  Licensed to the Apache Software Foundation (ASF) under one or more
    3    *  contributor license agreements.  See the NOTICE file distributed with
    4    *  this work for additional information regarding copyright ownership.
    5    *  The ASF licenses this file to You under the Apache License, Version 2.0
    6    *  (the "License"); you may not use this file except in compliance with
    7    *  the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    *  Unless required by applicable law or agreed to in writing, software
   12    *  distributed under the License is distributed on an "AS IS" BASIS,
   13    *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    *  See the License for the specific language governing permissions and
   15    *  limitations under the License.
   16    *
   17    */
   18   
   19   package org.apache.tools.ant.taskdefs;
   20   
   21   import java.io.File;
   22   import java.io.IOException;
   23   import java.io.PrintStream;
   24   import java.lang.reflect.InvocationTargetException;
   25   import java.lang.reflect.Method;
   26   import java.lang.reflect.Modifier;
   27   import org.apache.tools.ant.AntClassLoader;
   28   import org.apache.tools.ant.BuildException;
   29   import org.apache.tools.ant.Project;
   30   import org.apache.tools.ant.ProjectComponent;
   31   import org.apache.tools.ant.Task;
   32   import org.apache.tools.ant.taskdefs.condition.Os;
   33   import org.apache.tools.ant.types.Commandline;
   34   import org.apache.tools.ant.types.CommandlineJava;
   35   import org.apache.tools.ant.types.Path;
   36   import org.apache.tools.ant.types.Permissions;
   37   import org.apache.tools.ant.util.JavaEnvUtils;
   38   import org.apache.tools.ant.util.TimeoutObserver;
   39   import org.apache.tools.ant.util.Watchdog;
   40   
   41   /**
   42    * Execute a Java class.
   43    * @since Ant 1.2
   44    */
   45   public class ExecuteJava implements Runnable, TimeoutObserver {
   46   
   47       private Commandline javaCommand = null;
   48       private Path classpath = null;
   49       private CommandlineJava.SysProperties sysProperties = null;
   50       private Permissions  perm = null;
   51       private Method main = null;
   52       private Long timeout = null;
   53       private volatile Throwable caught = null;
   54       private volatile boolean timedOut = false;
   55       private Thread thread = null;
   56   
   57       /**
   58        * Set the Java "command" for this ExecuteJava.
   59        * @param javaCommand the classname and arguments in a Commandline.
   60        */
   61       public void setJavaCommand(Commandline javaCommand) {
   62           this.javaCommand = javaCommand;
   63       }
   64   
   65       /**
   66        * Set the classpath to be used when running the Java class.
   67        *
   68        * @param p an Ant Path object containing the classpath.
   69        */
   70       public void setClasspath(Path p) {
   71           classpath = p;
   72       }
   73   
   74       /**
   75        * Set the system properties to use when running the Java class.
   76        * @param s CommandlineJava system properties.
   77        */
   78       public void setSystemProperties(CommandlineJava.SysProperties s) {
   79           sysProperties = s;
   80       }
   81   
   82       /**
   83        * Set the permissions for the application run.
   84        * @param permissions the Permissions to use.
   85        * @since Ant 1.6
   86        */
   87       public void setPermissions(Permissions permissions) {
   88           perm = permissions;
   89       }
   90   
   91       /**
   92        * Set the stream to which all output (System.out as well as System.err)
   93        * will be written.
   94        * @param out the PrintStream where output should be sent.
   95        * @deprecated since 1.4.x.
   96        *             manage output at the task level.
   97        */
   98       public void setOutput(PrintStream out) {
   99       }
  100   
  101       /**
  102        * Set the timeout for this ExecuteJava.
  103        * @param timeout timeout as Long.
  104        * @since Ant 1.5
  105        */
  106       public void setTimeout(Long timeout) {
  107           this.timeout = timeout;
  108       }
  109   
  110       /**
  111        * Execute the Java class against the specified Ant Project.
  112        * @param project the Project to use.
  113        * @throws BuildException on error.
  114        */
  115       public void execute(Project project) throws BuildException {
  116           final String classname = javaCommand.getExecutable();
  117   
  118           AntClassLoader loader = null;
  119           try {
  120               if (sysProperties != null) {
  121                   sysProperties.setSystem();
  122               }
  123               Class target = null;
  124               try {
  125                   if (classpath == null) {
  126                       target = Class.forName(classname);
  127                   } else {
  128                       loader = project.createClassLoader(classpath);
  129                       loader.setParent(project.getCoreLoader());
  130                       loader.setParentFirst(false);
  131                       loader.addJavaLibraries();
  132                       loader.setIsolated(true);
  133                       loader.setThreadContextLoader();
  134                       loader.forceLoadClass(classname);
  135                       target = Class.forName(classname, true, loader);
  136                   }
  137               } catch (ClassNotFoundException e) {
  138                   throw new BuildException("Could not find " + classname + "."
  139                                            + " Make sure you have it in your"
  140                                            + " classpath");
  141               }
  142               main = target.getMethod("main", new Class[] {String[].class});
  143               if (main == null) {
  144                   throw new BuildException("Could not find main() method in "
  145                                            + classname);
  146               }
  147               if ((main.getModifiers() & Modifier.STATIC) == 0) {
  148                   throw new BuildException("main() method in " + classname
  149                       + " is not declared static");
  150               }
  151               if (timeout == null) {
  152                   run();
  153               } else {
  154                   thread = new Thread(this, "ExecuteJava");
  155                   Task currentThreadTask
  156                       = project.getThreadTask(Thread.currentThread());
  157                   // XXX is the following really necessary? it is in the same thread group...
  158                   project.registerThreadTask(thread, currentThreadTask);
  159                   // if we run into a timeout, the run-away thread shall not
  160                   // make the VM run forever - if no timeout occurs, Ant's
  161                   // main thread will still be there to let the new thread
  162                   // finish
  163                   thread.setDaemon(true);
  164                   Watchdog w = new Watchdog(timeout.longValue());
  165                   w.addTimeoutObserver(this);
  166                   synchronized (this) {
  167                       thread.start();
  168                       w.start();
  169                       try {
  170                           wait();
  171                       } catch (InterruptedException e) {
  172                           // ignore
  173                       }
  174                       if (timedOut) {
  175                           project.log("Timeout: sub-process interrupted",
  176                                       Project.MSG_WARN);
  177                       } else {
  178                           thread = null;
  179                           w.stop();
  180                       }
  181                   }
  182               }
  183               if (caught != null) {
  184                   throw caught;
  185               }
  186           } catch (BuildException e) {
  187               throw e;
  188           } catch (SecurityException e) {
  189               throw e;
  190           } catch (ThreadDeath e) {
  191               // XXX could perhaps also call thread.stop(); not sure if anyone cares
  192               throw e;
  193           } catch (Throwable e) {
  194               throw new BuildException(e);
  195           } finally {
  196               if (loader != null) {
  197                   loader.resetThreadContextLoader();
  198                   loader.cleanup();
  199                   loader = null;
  200               }
  201               if (sysProperties != null) {
  202                   sysProperties.restoreSystem();
  203               }
  204           }
  205       }
  206   
  207       /**
  208        * Run this ExecuteJava in a Thread.
  209        * @since Ant 1.5
  210        */
  211       public void run() {
  212           final Object[] argument = {javaCommand.getArguments()};
  213           try {
  214               if (perm != null) {
  215                   perm.setSecurityManager();
  216               }
  217               main.invoke(null, argument);
  218           } catch (InvocationTargetException e) {
  219               Throwable t = e.getTargetException();
  220               if (!(t instanceof InterruptedException)) {
  221                   caught = t;
  222               } /* else { swallow, probably due to timeout } */
  223           } catch (Throwable t) {
  224               caught = t;
  225           } finally {
  226               if (perm != null) {
  227                   perm.restoreSecurityManager();
  228               }
  229               synchronized (this) {
  230                   notifyAll();
  231               }
  232           }
  233       }
  234   
  235       /**
  236        * Mark timeout as having occurred.
  237        * @param w the responsible Watchdog.
  238        * @since Ant 1.5
  239        */
  240       public synchronized void timeoutOccured(Watchdog w) {
  241           if (thread != null) {
  242               timedOut = true;
  243               thread.interrupt();
  244           }
  245           notifyAll();
  246       }
  247   
  248       /**
  249        * Get whether the process was killed.
  250        * @return <code>true</code> if the process was killed, false otherwise.
  251        * @since 1.19, Ant 1.5
  252        */
  253       public synchronized boolean killedProcess() {
  254           return timedOut;
  255       }
  256   
  257       /**
  258        * Run the Java command in a separate VM, this does not give you
  259        * the full flexibility of the Java task, but may be enough for
  260        * simple needs.
  261        * @param pc the ProjectComponent to use for logging, etc.
  262        * @return the exit status of the subprocess.
  263        * @throws BuildException on error.
  264        * @since Ant 1.6.3
  265        */
  266       public int fork(ProjectComponent pc) throws BuildException {
  267           CommandlineJava cmdl = new CommandlineJava();
  268           cmdl.setClassname(javaCommand.getExecutable());
  269           String[] args = javaCommand.getArguments();
  270           for (int i = 0; i < args.length; i++) {
  271               cmdl.createArgument().setValue(args[i]);
  272           }
  273           if (classpath != null) {
  274               cmdl.createClasspath(pc.getProject()).append(classpath);
  275           }
  276           if (sysProperties != null) {
  277               cmdl.addSysproperties(sysProperties);
  278           }
  279           Redirector redirector = new Redirector(pc);
  280           Execute exe
  281               = new Execute(redirector.createHandler(),
  282                             timeout == null
  283                             ? null
  284                             : new ExecuteWatchdog(timeout.longValue()));
  285           exe.setAntRun(pc.getProject());
  286           if (Os.isFamily("openvms")) {
  287               setupCommandLineForVMS(exe, cmdl.getCommandline());
  288           } else {
  289               exe.setCommandline(cmdl.getCommandline());
  290           }
  291           try {
  292               int rc = exe.execute();
  293               redirector.complete();
  294               return rc;
  295           } catch (IOException e) {
  296               throw new BuildException(e);
  297           } finally {
  298               timedOut = exe.killedProcess();
  299           }
  300       }
  301   
  302       /**
  303        * On VMS platform, we need to create a special java options file
  304        * containing the arguments and classpath for the java command.
  305        * The special file is supported by the "-V" switch on the VMS JVM.
  306        *
  307        * @param exe the Execute instance to alter.
  308        * @param command the command-line.
  309        */
  310       public static void setupCommandLineForVMS(Execute exe, String[] command) {
  311           //Use the VM launcher instead of shell launcher on VMS
  312           exe.setVMLauncher(true);
  313           File vmsJavaOptionFile = null;
  314           try {
  315               String [] args = new String[command.length - 1];
  316               System.arraycopy(command, 1, args, 0, command.length - 1);
  317               vmsJavaOptionFile = JavaEnvUtils.createVmsJavaOptionFile(args);
  318               //we mark the file to be deleted on exit.
  319               //the alternative would be to cache the filename and delete
  320               //after execution finished, which is much better for long-lived runtimes
  321               //though spawning complicates things...
  322               vmsJavaOptionFile.deleteOnExit();
  323               String [] vmsCmd = {command[0], "-V", vmsJavaOptionFile.getPath()};
  324               exe.setCommandline(vmsCmd);
  325           } catch (IOException e) {
  326               throw new BuildException("Failed to create a temporary file for \"-V\" switch");
  327           }
  328       }
  329   
  330   }

Save This Page
Home » apache-ant-1.7.1-src » org.apache.tools » ant » taskdefs » [javadoc | source]