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      protected AbstractJavaTool( String javaToolName )
63      {
64          this.javaToolName = javaToolName;
65      }
66  
67      /**
68       * Create the commandline object given the request.
69       *
70       * @param request      User request on the java tool
71       * @param javaToolFile Location of the java tool file to use
72       * @return the commandline
73       * @throws JavaToolException if could not create the command line from the request
74       */
75      protected abstract Commandline createCommandLine( Request request, String javaToolFile )
76          throws JavaToolException;
77  
78      /**
79       * {@inheritDoc}
80       */
81      public String getJavaToolName()
82      {
83          return javaToolName;
84      }
85  
86      /**
87       * {@inheritDoc}
88       */
89      public void setToolchain( Toolchain toolchain )
90      {
91          this.toolchain = toolchain;
92      }
93  
94      /**
95       * {@inheritDoc}
96       */
97      public JavaToolResult execute( Request request )
98          throws JavaToolException
99      {
100 
101         if ( javaToolFile == null )
102         {
103 
104             // find the java tool file to use
105             try
106             {
107                 javaToolFile = findJavaToolExecutable();
108             }
109             catch ( Exception e )
110             {
111                 throw new JavaToolException( "Error finding " + javaToolName + " executable. Reason: " + e.getMessage(),
112                                              e );
113             }
114         }
115 
116         // creates the command line from the given request
117         Commandline cli = createCommandLine( request, javaToolFile );
118 
119         // execute it
120         JavaToolResult result = executeCommandLine( cli, request );
121 
122         // return result
123         return result;
124     }
125 
126     protected InputStream createSystemInputStream()
127     {
128         InputStream systemIn = new InputStream()
129         {
130 
131             /**
132              * {@inheritDoc}
133              */
134             public int read()
135             {
136                 return -1;
137             }
138 
139         };
140         return systemIn;
141     }
142 
143     protected JavaToolResult executeCommandLine( Commandline cli, Request request )
144     {
145         if ( getLogger().isDebugEnabled() )
146         {
147             getLogger().debug( "Executing: " + cli );
148         }
149 
150         JavaToolResult result = createResult();
151 
152         result.setCommandline( cli );
153 
154         InputStream systemIn = createSystemInputStream();
155 
156         StreamConsumer systemOut = createSystemOutStreamConsumer( request );
157 
158         StreamConsumer systemErr = createSystemErrorStreamConsumer( request );
159 
160         try
161         {
162             int resultCode = CommandLineUtils.executeCommandLine( cli, systemIn, systemOut, systemErr );
163 
164             result.setExitCode( resultCode );
165         }
166         catch ( CommandLineException e )
167         {
168             result.setExecutionException( e );
169         }
170 
171         return result;
172     }
173 
174     protected StreamConsumer createSystemErrorStreamConsumer( Request request )
175     {
176         StreamConsumer systemErr = request.getSystemErrorStreamConsumer();
177 
178         if ( systemErr == null )
179         {
180             systemErr = new StreamConsumer()
181             {
182 
183                 /**
184                  * {@inheritDoc}
185                  */
186                 public void consumeLine( final String line )
187                 {
188                     getLogger().warn( line );
189                 }
190 
191             };
192         }
193         return systemErr;
194     }
195 
196     protected StreamConsumer createSystemOutStreamConsumer( Request request )
197     {
198         StreamConsumer systemOut = request.getSystemOutStreamConsumer();
199 
200         if ( systemOut == null )
201         {
202 
203             systemOut = new StreamConsumer()
204             {
205 
206                 /**
207                  * {@inheritDoc}
208                  */
209                 public void consumeLine( final String line )
210                 {
211                     getLogger().info( line );
212 
213                 }
214 
215             };
216         }
217         return systemOut;
218     }
219 
220     protected JavaToolResult createResult()
221     {
222         return new JavaToolResult();
223     }
224 
225     protected String findJavaToolExecutable()
226     {
227         String command = javaToolName + ( Os.isFamily( Os.FAMILY_WINDOWS ) ? ".exe" : "" );
228 
229         String executable = null;
230 
231         if ( toolchain != null )
232         {
233             executable = toolchain.findTool( javaToolName );
234         }
235 
236         if ( executable == null )
237         {
238             executable = findExecutable( command, System.getProperty( "java.home" ), "../bin", "bin", "../sh" );
239         }
240 
241         if ( executable == null )
242         {
243 
244             Map<String, String> env = System.getenv();
245 
246             String[] variables = { "JDK_HOME", "JAVA_HOME" };
247 
248             for ( String variable : variables )
249             {
250                 executable = findExecutable( command, env.get( variable ), "bin", "sh" );
251                 if ( executable != null )
252                 {
253                     break;
254                 }
255             }
256         }
257 
258         if ( executable == null )
259         {
260             executable = command;
261         }
262 
263         return executable;
264     }
265 
266     /**
267      * Finds the specified command in any of the given sub directories of the specified JDK/JRE home directory.
268      *
269      * @param command The command to find, must not be <code>null</code>.
270      * @param homeDir The home directory to search in, may be <code>null</code>.
271      * @param subDirs The sub directories of the home directory to search in, must not be <code>null</code>.
272      * @return The (absolute) path to the command if found, <code>null</code> otherwise.
273      */
274     private String findExecutable( String command, String homeDir, String... subDirs )
275     {
276         String result = null;
277         if ( StringUtils.isNotEmpty( homeDir ) )
278         {
279             for ( String subDir : subDirs )
280             {
281                 File file = new File( new File( homeDir, subDir ), command );
282 
283                 if ( file.isFile() )
284                 {
285                     result = file.getAbsolutePath();
286                     break;
287                 }
288             }
289         }
290 
291         return result;
292     }
293 }