View Javadoc

1   /*
2    * Copyright 2007 scala-tools.org
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *    http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing,
11   * software distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions
14   * and limitations under the License.
15   */
16  package org.scala_tools.maven;
17  
18  import java.io.File;
19  import java.net.URL;
20  import java.net.URLClassLoader;
21  import java.util.ArrayList;
22  import java.util.List;
23  
24  import org.apache.maven.plugin.AbstractMojo;
25  import org.apache.maven.plugin.MojoFailureException;
26  import org.codehaus.plexus.util.DirectoryScanner;
27  import org.codehaus.plexus.util.StringUtils;
28  
29  /**
30   * Helper class use to call a java Main in an external process.
31   */
32  public class JavaCommand {
33      // //////////////////////////////////////////////////////////////////////////
34      // Class
35      // //////////////////////////////////////////////////////////////////////////
36      public static String toMultiPath(List<String> paths) {
37          return StringUtils.join(paths.iterator(), File.pathSeparator);
38      }
39  
40      public static String toMultiPath(String[] paths) {
41          return StringUtils.join(paths, File.pathSeparator);
42      }
43  
44      public static String[] findFiles(File dir, String pattern) {
45          DirectoryScanner scanner = new DirectoryScanner();
46          scanner.setBasedir(dir);
47          scanner.setIncludes(new String[] { pattern });
48          scanner.addDefaultExcludes();
49          scanner.scan();
50          return scanner.getIncludedFiles();
51      }
52  
53      public static String toClasspathString(ClassLoader cl) throws Exception {
54          if (cl == null) {
55              cl = Thread.currentThread().getContextClassLoader();
56          }
57          StringBuilder back = new StringBuilder();
58          while (cl != null) {
59              if (cl instanceof URLClassLoader) {
60                  URLClassLoader ucl = (URLClassLoader) cl;
61                  URL[] urls = ucl.getURLs();
62                  for (URL url : urls) {
63                      if (back.length() != 0) {
64                          back.append(File.pathSeparatorChar);
65                      }
66                      back.append(url.getFile());
67                  }
68              }
69              cl = cl.getParent();
70          }
71          return back.toString();
72      }
73  
74      // //////////////////////////////////////////////////////////////////////////
75      // Object
76      // //////////////////////////////////////////////////////////////////////////
77      private AbstractMojo requester_;
78  
79      private List<String> env_;
80      private List<String> jvmArgs_;
81      private List<String> args_;
82      private String javaExec_;
83      private String mainClassName_;
84      private boolean logOnly_ = true;
85  
86      public JavaCommand(AbstractMojo requester, String mainClassName, String classpath, String[] jvmArgs, String[] args) throws Exception {
87          requester_ = requester;
88          env_ = new ArrayList<String>();
89          for (String key : System.getenv().keySet()) {
90              env_.add(key + "=" + System.getenv(key));
91          }
92          javaExec_ = System.getProperty("java.home");
93          if (javaExec_ == null) {
94              javaExec_ = System.getenv("JAVA_HOME");
95              if (javaExec_ == null) {
96                  throw new IllegalStateException("Couldn't locate java, try setting JAVA_HOME environment variable.");
97              }
98          }
99          javaExec_ += File.separator + "bin" + File.separator + "java";
100         mainClassName_ = mainClassName;
101         jvmArgs_ = new ArrayList<String>();
102         args_ = new ArrayList<String>();
103         addJvmArgs("-classpath", classpath);
104         addJvmArgs(jvmArgs);
105         addArgs(args);
106     }
107 
108     public void addEnvVar(String key, String value) {
109         env_.add(key + "=" + value);
110     }
111 
112     public void addJvmArgs(String... args) {
113         if (args == null) {
114             return;
115         }
116         for (String arg : args) {
117             jvmArgs_.add(arg);
118         }
119     }
120 
121     public void addArgs(String... args) {
122         if (args == null) {
123             return;
124         }
125         for (String arg : args) {
126             args_.add(arg);
127         }
128     }
129 
130     public void addOption(String key, String value) {
131         if ((value == null) || (key == null)) {
132             return;
133         }
134         args_.add(key);
135         args_.add(value);
136     }
137 
138     public void addOption(String key, File value) {
139         if ((value == null) || (key == null)) {
140             return;
141         }
142         args_.add(key);
143         args_.add(value.getAbsolutePath());
144     }
145 
146     public void addOption(String key, boolean value) {
147         if ((!value) || (key == null)) {
148             return;
149         }
150         args_.add(key);
151     }
152 
153     public void setLogOnly(boolean v) {
154         logOnly_ = v;
155     }
156 
157     private String[] buildCommand() {
158         ArrayList<String> back = new ArrayList<String>(2 + jvmArgs_.size() + args_.size());
159         back.add(javaExec_);
160         back.addAll(jvmArgs_);
161         back.add(mainClassName_);
162         back.addAll(args_);
163         return back.toArray(new String[back.size()]);
164     }
165 
166     // TODO: avoid to have several Thread to pipe stream
167     // TODO: add support to inject startup command and shutdown command (on :quit)
168     public void run(boolean displayCmd) throws Exception {
169         run(displayCmd, true);
170     }
171 
172     public void run(boolean displayCmd, boolean throwFailure) throws Exception {
173 
174         String[] cmd = buildCommand();
175         if (displayCmd) {
176             requester_.getLog().info("cmd: " + " " + StringUtils.join(cmd, " "));
177         } else if (requester_.getLog().isDebugEnabled()) {
178             requester_.getLog().debug("cmd: " + " " + StringUtils.join(cmd, " "));
179         }
180         ProcessBuilder pb = new ProcessBuilder(cmd);
181         //pb.directory("myDir");
182         if (!logOnly_) {
183             pb = pb.redirectErrorStream(true);
184         }
185         Process p = pb.start();
186         if (logOnly_) {
187             new StreamLogger(p.getErrorStream(), requester_.getLog(), true).start();
188             new StreamLogger(p.getInputStream(), requester_.getLog(), false).start();
189         } else {
190             new StreamPiper(p.getInputStream(), System.out).start();
191             //new StreamPiper(System.in, p.getOutputStream()).start();
192             new ConsolePiper(p).start();
193         }
194         int retVal = p.waitFor();
195         if (throwFailure && (retVal != 0)) {
196             throw new MojoFailureException("command line returned non-zero value:" + retVal);
197         }
198     }
199 
200     /**
201      * run the command without stream redirection nor waiting for exit
202      *
203      * @param displayCmd
204      * @throws Exception
205      */
206     public void spawn(boolean displayCmd) throws Exception {
207         String[] cmd = buildCommand();
208         if (displayCmd) {
209             requester_.getLog().info("cmd: " + " " + StringUtils.join(cmd, " "));
210         } else if (requester_.getLog().isDebugEnabled()) {
211             requester_.getLog().debug("cmd: " + " " + StringUtils.join(cmd, " "));
212         }
213         ProcessBuilder pb = new ProcessBuilder(cmd);
214         pb.start();
215     }
216 
217 }