View Javadoc
1   package org.apache.maven.shared.utils.cli.javatool;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.maven.shared.utils.Os;
23  import org.apache.maven.shared.utils.StringUtils;
24  import org.apache.maven.shared.utils.cli.CommandLineException;
25  import org.apache.maven.shared.utils.cli.CommandLineUtils;
26  import org.apache.maven.shared.utils.cli.Commandline;
27  import org.apache.maven.shared.utils.cli.StreamConsumer;
28  import org.apache.maven.toolchain.Toolchain;
29  import org.codehaus.plexus.logging.AbstractLogEnabled;
30  
31  import java.io.File;
32  import java.io.InputStream;
33  import java.util.Map;
34  
35  /**
36   * Abstract implementation of a {@link JavaTool}.
37   *
38   * @author Tony Chemit <chemit@codelutin.com>
39   * @since 0.5
40   * @param <Request>
41   */
42  public abstract class AbstractJavaTool<Request extends JavaToolRequest>
43      extends AbstractLogEnabled
44      implements JavaTool<Request>
45  {
46  
47      /**
48       * The java tool name to find out in the jdk.
49       */
50      private final String javaToolName;
51  
52      /**
53       * The location of the java tool executable file.
54       */
55      private String javaToolFile;
56  
57      /**
58       * Optional toolChain used to find java tool executable file.
59       */
60      private Toolchain toolchain;
61  
62      /**
63       * @param javaToolName The name of the java tool.
64       */
65      protected AbstractJavaTool( String javaToolName )
66      {
67          this.javaToolName = javaToolName;
68      }
69  
70      /**
71       * Create the command line object given the request.
72       *
73       * @param request      User request on the java tool
74       * @param javaToolFileLocation Location of the java tool file to use
75       * @return the command line
76       * @throws JavaToolException if could not create the command line from the request
77       */
78      protected abstract Commandline createCommandLine( Request request, String javaToolFileLocation )
79          throws JavaToolException;
80  
81      /**
82       * {@inheritDoc}
83       */
84      public String getJavaToolName()
85      {
86          return javaToolName;
87      }
88  
89      /**
90       * {@inheritDoc}
91       */
92      public void setToolchain( Toolchain toolchain )
93      {
94          this.toolchain = toolchain;
95      }
96  
97      /**
98       * {@inheritDoc}
99       */
100     public JavaToolResult execute( Request request )
101         throws JavaToolException
102     {
103 
104         if ( javaToolFile == null )
105         {
106 
107             // find the java tool file to use
108             try
109             {
110                 javaToolFile = findJavaToolExecutable();
111             }
112             catch ( Exception e )
113             {
114                 throw new JavaToolException( "Error finding " + javaToolName + " executable. Reason: " + e.getMessage(),
115                                              e );
116             }
117         }
118 
119         // creates the command line from the given request
120         Commandline cli = createCommandLine( request, javaToolFile );
121 
122         // execute it
123         JavaToolResult result = executeCommandLine( cli, request );
124 
125         // return result
126         return result;
127     }
128 
129     /**
130      * @return {@link InputStream}
131      */
132     protected InputStream createSystemInputStream()
133     {
134         InputStream systemIn = new InputStream()
135         {
136 
137             /**
138              * {@inheritDoc}
139              */
140             public int read()
141             {
142                 return -1;
143             }
144 
145         };
146         return systemIn;
147     }
148 
149     /**
150      * @param cli {@link Commandline}
151      * @param request The request.
152      * @return {@link JavaToolRequest}
153      */
154     protected JavaToolResult executeCommandLine( Commandline cli, Request request )
155     {
156         if ( getLogger().isDebugEnabled() )
157         {
158             getLogger().debug( "Executing: " + cli );
159         }
160 
161         JavaToolResult result = createResult();
162 
163         result.setCommandline( cli );
164 
165         InputStream systemIn = createSystemInputStream();
166 
167         StreamConsumer systemOut = createSystemOutStreamConsumer( request );
168 
169         StreamConsumer systemErr = createSystemErrorStreamConsumer( request );
170 
171         try
172         {
173             int resultCode = CommandLineUtils.executeCommandLine( cli, systemIn, systemOut, systemErr );
174 
175             result.setExitCode( resultCode );
176         }
177         catch ( CommandLineException e )
178         {
179             result.setExecutionException( e );
180         }
181 
182         return result;
183     }
184 
185     /**
186      * @param request The request.
187      * @return {@link StreamConsumer}
188      */
189     protected StreamConsumer createSystemErrorStreamConsumer( Request request )
190     {
191         StreamConsumer systemErr = request.getSystemErrorStreamConsumer();
192 
193         if ( systemErr == null )
194         {
195             systemErr = new StreamConsumer()
196             {
197 
198                 /**
199                  * {@inheritDoc}
200                  */
201                 public void consumeLine( final String line )
202                 {
203                     getLogger().warn( line );
204                 }
205 
206             };
207         }
208         return systemErr;
209     }
210 
211     /**
212      * @param request The request.
213      * @return {@link StreamConsumer}
214      */
215     protected StreamConsumer createSystemOutStreamConsumer( Request request )
216     {
217         StreamConsumer systemOut = request.getSystemOutStreamConsumer();
218 
219         if ( systemOut == null )
220         {
221 
222             systemOut = new StreamConsumer()
223             {
224 
225                 /**
226                  * {@inheritDoc}
227                  */
228                 public void consumeLine( final String line )
229                 {
230                     getLogger().info( line );
231 
232                 }
233 
234             };
235         }
236         return systemOut;
237     }
238 
239     /**
240      * @return The JavaToolResult.
241      */
242     protected JavaToolResult createResult()
243     {
244         return new JavaToolResult();
245     }
246 
247     /**
248      * @return The location of the java tool executable.
249      */
250     protected String findJavaToolExecutable()
251     {
252         String command = javaToolName + ( Os.isFamily( Os.FAMILY_WINDOWS ) ? ".exe" : "" );
253 
254         String executable = null;
255 
256         if ( toolchain != null )
257         {
258             executable = toolchain.findTool( javaToolName );
259         }
260 
261         if ( executable == null )
262         {
263             executable = findExecutable( command, System.getProperty( "java.home" ), "../bin", "bin", "../sh" );
264         }
265 
266         if ( executable == null )
267         {
268 
269             Map<String, String> env = System.getenv();
270 
271             String[] variables = { "JDK_HOME", "JAVA_HOME" };
272 
273             for ( String variable : variables )
274             {
275                 executable = findExecutable( command, env.get( variable ), "bin", "sh" );
276                 if ( executable != null )
277                 {
278                     break;
279                 }
280             }
281         }
282 
283         if ( executable == null )
284         {
285             executable = command;
286         }
287 
288         return executable;
289     }
290 
291     /**
292      * Finds the specified command in any of the given sub directories of the specified JDK/JRE home directory.
293      *
294      * @param command The command to find, must not be <code>null</code>.
295      * @param homeDir The home directory to search in, may be <code>null</code>.
296      * @param subDirs The sub directories of the home directory to search in, must not be <code>null</code>.
297      * @return The (absolute) path to the command if found, <code>null</code> otherwise.
298      */
299     private String findExecutable( String command, String homeDir, String... subDirs )
300     {
301         String result = null;
302         if ( StringUtils.isNotEmpty( homeDir ) )
303         {
304             for ( String subDir : subDirs )
305             {
306                 File file = new File( new File( homeDir, subDir ), command );
307 
308                 if ( file.isFile() )
309                 {
310                     result = file.getAbsolutePath();
311                     break;
312                 }
313             }
314         }
315 
316         return result;
317     }
318 }