View Javadoc

1   package org.apache.continuum.installation;
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 java.io.File;
23  import java.io.IOException;
24  import java.util.ArrayList;
25  import java.util.Collections;
26  import java.util.HashMap;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.Properties;
30  
31  import javax.annotation.Resource;
32  
33  import org.apache.continuum.dao.InstallationDao;
34  import org.apache.maven.continuum.execution.ExecutorConfigurator;
35  import org.apache.maven.continuum.installation.AlreadyExistsInstallationException;
36  import org.apache.maven.continuum.installation.InstallationException;
37  import org.apache.maven.continuum.installation.InstallationService;
38  import org.apache.maven.continuum.model.system.Installation;
39  import org.apache.maven.continuum.model.system.Profile;
40  import org.apache.maven.continuum.profile.AlreadyExistsProfileException;
41  import org.apache.maven.continuum.profile.ProfileException;
42  import org.apache.maven.continuum.profile.ProfileService;
43  import org.apache.maven.continuum.store.ContinuumStoreException;
44  import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
45  import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
46  import org.codehaus.plexus.util.StringUtils;
47  import org.codehaus.plexus.util.cli.CommandLineException;
48  import org.codehaus.plexus.util.cli.CommandLineUtils;
49  import org.codehaus.plexus.util.cli.Commandline;
50  import org.codehaus.plexus.util.cli.StreamConsumer;
51  import org.slf4j.Logger;
52  import org.slf4j.LoggerFactory;
53  import org.springframework.stereotype.Service;
54  
55  /**
56   * @author <a href="mailto:olamy@codehaus.org">olamy</a>
57   * @version $Id: DefaultInstallationService.java 767304 2009-04-21 21:32:15Z evenisse $
58   *          TODO use some cache mechanism to prevent always reading from store ?
59   * @since 13 juin 07
60   */
61  @Service("installationService")
62  public class DefaultInstallationService
63      implements InstallationService, Initializable
64  {
65      private static final Logger log = LoggerFactory.getLogger( DefaultInstallationService.class );
66  
67      @Resource
68      private InstallationDao installationDao;
69  
70      @Resource
71      private ProfileService profileService;
72  
73      private Map<String, ExecutorConfigurator> typesValues;
74  
75      // ---------------------------------------------
76      // Plexus lifecycle
77      // ---------------------------------------------
78  
79      public void initialize()
80          throws InitializationException
81      {
82          this.typesValues = new HashMap<String, ExecutorConfigurator>();
83          this.typesValues.put( InstallationService.ANT_TYPE,
84                                new ExecutorConfigurator( "ant", "bin", "ANT_HOME", "-version" ) );
85  
86          this.typesValues.put( InstallationService.ENVVAR_TYPE, null );
87          this.typesValues.put( InstallationService.JDK_TYPE,
88                                new ExecutorConfigurator( "java", "bin", "JAVA_HOME", "-version" ) );
89          this.typesValues.put( InstallationService.MAVEN1_TYPE,
90                                new ExecutorConfigurator( "maven", "bin", "MAVEN_HOME", "-v" ) );
91          this.typesValues.put( InstallationService.MAVEN2_TYPE,
92                                new ExecutorConfigurator( "mvn", "bin", "M2_HOME", "-v" ) );
93      }
94  
95      /**
96       * @see org.apache.maven.continuum.installation.InstallationService#add(org.apache.maven.continuum.model.system.Installation)
97       */
98      public Installation add( Installation installation )
99          throws InstallationException, AlreadyExistsInstallationException
100     {
101         try
102         {
103             return this.add( installation, false );
104         }
105         catch ( AlreadyExistsProfileException e )
106         {
107             // normally cannot happend here but anyway we throw the exception
108             throw new InstallationException( e.getMessage(), e );
109         }
110     }
111 
112     public Installation add( Installation installation, boolean automaticProfile )
113         throws InstallationException, AlreadyExistsProfileException, AlreadyExistsInstallationException
114     {
115         if ( alreadyExistInstallationName( installation ) )
116         {
117             throw new AlreadyExistsInstallationException(
118                 "Installation with name " + installation.getName() + " already exists" );
119         }
120         // TODO must be done in the same transaction
121         Installation storedOne;
122         try
123         {
124             String envVarName = this.getEnvVar( installation.getType() );
125             // override with the defined var name for defined types
126             if ( StringUtils.isNotEmpty( envVarName ) )
127             {
128                 installation.setVarName( envVarName );
129             }
130             storedOne = installationDao.addInstallation( installation );
131         }
132         catch ( ContinuumStoreException e )
133         {
134             throw new InstallationException( e.getMessage(), e );
135         }
136         try
137         {
138             if ( automaticProfile )
139             {
140                 Profile profile = new Profile();
141                 profile.setName( storedOne.getName() );
142                 profile = profileService.addProfile( profile );
143                 profileService.addInstallationInProfile( profile, storedOne );
144             }
145         }
146         catch ( ProfileException e )
147         {
148             throw new InstallationException( "failed to create automatic Profile " + e.getMessage(), e );
149         }
150         return storedOne;
151     }
152 
153     /**
154      * @see org.apache.maven.continuum.installation.InstallationService#delete(org.apache.maven.continuum.model.system.Installation)
155      */
156     public void delete( Installation installation )
157         throws InstallationException
158     {
159         try
160         {
161             installationDao.removeInstallation( installation );
162         }
163         catch ( ContinuumStoreException e )
164         {
165             throw new InstallationException( e.getMessage(), e );
166         }
167 
168     }
169 
170     /**
171      * @see org.apache.maven.continuum.installation.InstallationService#getAllInstallations()
172      */
173     @SuppressWarnings("unchecked")
174     public List<Installation> getAllInstallations()
175         throws InstallationException
176     {
177         try
178         {
179             List<Installation> installations = installationDao.getAllInstallations();
180             return installations == null ? Collections.EMPTY_LIST : installations;
181         }
182         catch ( ContinuumStoreException e )
183         {
184             throw new InstallationException( e.getMessage(), e );
185         }
186     }
187 
188     /**
189      * @see org.apache.maven.continuum.installation.InstallationService#getInstallation(int)
190      */
191     public Installation getInstallation( int installationId )
192         throws InstallationException
193     {
194         try
195         {
196             return installationDao.getInstallation( installationId );
197         }
198         catch ( ContinuumStoreException e )
199         {
200             throw new InstallationException( e.getMessage(), e );
201         }
202     }
203 
204     /**
205      * @see org.apache.maven.continuum.installation.InstallationService#update(org.apache.maven.continuum.model.system.Installation)
206      */
207     public void update( Installation installation )
208         throws InstallationException, AlreadyExistsInstallationException
209     {
210         try
211         {
212             Installation stored = getInstallation( installation.getInstallationId() );
213             if ( stored == null )
214             {
215                 throw new InstallationException( "installation with name " + installation.getName() + " not exists" );
216             }
217 
218             stored.setName( installation.getName() );
219             if ( alreadyExistInstallationName( installation ) )
220             {
221                 throw new AlreadyExistsInstallationException(
222                     "Installation with name " + installation.getName() + " already exists" );
223             }
224             stored.setType( installation.getType() );
225             String envVarName = this.getEnvVar( installation.getType() );
226             // override with the defined var name for defined types
227             if ( StringUtils.isNotEmpty( envVarName ) )
228             {
229                 installation.setVarName( envVarName );
230             }
231             else
232             {
233                 stored.setVarName( installation.getVarName() );
234             }
235             stored.setVarValue( installation.getVarValue() );
236             installationDao.updateInstallation( stored );
237         }
238         catch ( ContinuumStoreException e )
239         {
240             throw new InstallationException( e.getMessage(), e );
241         }
242 
243     }
244 
245     /**
246      * @see org.apache.maven.continuum.installation.InstallationService#getExecutorConfigurator(java.lang.String)
247      */
248     public ExecutorConfigurator getExecutorConfigurator( String type )
249     {
250         return this.typesValues.get( type );
251     }
252 
253     /**
254      * @see org.apache.maven.continuum.installation.InstallationService#getEnvVar(java.lang.String)
255      */
256     public String getEnvVar( String type )
257     {
258         ExecutorConfigurator executorConfigurator = this.typesValues.get( type );
259         return executorConfigurator == null ? null : executorConfigurator.getEnvVar();
260     }
261 
262     // -------------------------------------------------------------
263     // versions informations on jdk and builders (mvn, maven, ant )
264     // -------------------------------------------------------------
265 
266     /**
267      * TODO replace with calling getExecutorConfiguratorVersion
268      *
269      * @see org.apache.maven.continuum.installation.InstallationService#getDefaultJdkInformations()
270      */
271     public List<String> getDefaultJdkInformations()
272         throws InstallationException
273     {
274         try
275         {
276             Properties systemEnvVars = CommandLineUtils.getSystemEnvVars( false );
277 
278             String javaHome = (String) systemEnvVars.get( "JAVA_HOME" );
279             // olamy : JAVA_HOME can not exists with a mac user
280             if ( StringUtils.isEmpty( javaHome ) )
281             {
282                 return getJavaHomeInformations( System.getProperty( "java.home" ) );
283             }
284             return getJavaHomeInformations( javaHome );
285 
286         }
287         catch ( IOException e )
288         {
289             throw new InstallationException( e.getMessage(), e );
290         }
291         catch ( CommandLineException e )
292         {
293             throw new InstallationException( e.getMessage(), e );
294         }
295     }
296 
297     /**
298      * TODO replace with calling getExecutorConfiguratorVersion
299      *
300      * @see org.apache.maven.continuum.installation.InstallationService#getJdkInformations(org.apache.maven.continuum.model.system.Installation)
301      */
302     public List<String> getJdkInformations( Installation installation )
303         throws InstallationException
304     {
305         if ( installation == null )
306         {
307             return getDefaultJdkInformations();
308         }
309         if ( StringUtils.isEmpty( installation.getVarValue() ) )
310         {
311             return getDefaultJdkInformations();
312         }
313         try
314         {
315             return getJavaHomeInformations( installation.getVarValue() );
316         }
317         catch ( CommandLineException e )
318         {
319             throw new InstallationException( e.getMessage(), e );
320         }
321     }
322 
323     /**
324      * @param javaHome
325      * @return
326      * @throws CommandLineException
327      */
328     private List<String> getJavaHomeInformations( String javaHome )
329         throws CommandLineException
330     {
331         Commandline commandline = new Commandline();
332 
333         String executable = javaHome + File.separator + "bin" + File.separator + "java";
334 
335         commandline.setExecutable( executable );
336         commandline.addArguments( new String[]{"-version"} );
337         final List<String> cliOutput = new ArrayList<String>();
338         //TODO ShellCommandHelper ?
339         int result = CommandLineUtils.executeCommandLine( commandline, new StreamConsumer()
340         {
341             public void consumeLine( String line )
342             {
343                 cliOutput.add( line );
344             }
345         }, new StreamConsumer()
346         {
347             public void consumeLine( String line )
348             {
349                 cliOutput.add( line );
350             }
351         } );
352         if ( result != 0 )
353         {
354             throw new CommandLineException( "cli to get JAVA_HOME informations return code " + result );
355         }
356         return cliOutput;
357     }
358 
359     private Map<String, String> getEnvVars( Profile profile )
360     {
361         Map<String, String> environnments = new HashMap<String, String>();
362         if ( profile == null )
363         {
364             return environnments;
365         }
366         if ( profile.getBuilder() != null )
367         {
368             environnments.put( profile.getBuilder().getVarName(), profile.getBuilder().getVarValue() );
369         }
370         if ( profile.getJdk() != null )
371         {
372             environnments.put( profile.getJdk().getVarName(), profile.getJdk().getVarValue() );
373         }
374         if ( profile.getEnvironmentVariables() != null )
375         {
376             for ( Installation installation : (List<Installation>) profile.getEnvironmentVariables() )
377             {
378                 environnments.put( installation.getVarName(), installation.getVarValue() );
379             }
380         }
381         return environnments;
382     }
383 
384     /**
385      * @see org.apache.maven.continuum.installation.InstallationService#getExecutorConfiguratorVersion(java.lang.String,org.apache.maven.continuum.execution.ExecutorConfigurator,Profile)
386      */
387     @SuppressWarnings("unchecked")
388     public List<String> getExecutorConfiguratorVersion( String path, ExecutorConfigurator executorConfigurator,
389                                                         Profile profile )
390         throws InstallationException
391     {
392 
393         if ( executorConfigurator == null )
394         {
395             return Collections.EMPTY_LIST;
396         }
397         if ( executorConfigurator.getExecutable() == null )
398         {
399             return Collections.EMPTY_LIST;
400         }
401         StringBuilder executable = new StringBuilder();
402         try
403         {
404             Commandline commandline = new Commandline();
405             if ( StringUtils.isNotEmpty( path ) )
406             {
407                 executable.append( path ).append( File.separator );
408                 executable.append( executorConfigurator.getRelativePath() ).append( File.separator );
409                 commandline.addEnvironment( executorConfigurator.getEnvVar(), path );
410             }
411             //Installations are env var they must be add if exists
412             Map<String, String> environments = getEnvVars( profile );
413             // no null check we use a private method just here
414             for ( String key : environments.keySet() )
415             {
416                 String value = environments.get( key );
417                 commandline.addEnvironment( key, value );
418             }
419 
420             executable = executable.append( executorConfigurator.getExecutable() );
421             commandline.setExecutable( executable.toString() );
422             commandline.addArguments( new String[]{executorConfigurator.getVersionArgument()} );
423             final List<String> cliOutput = new ArrayList<String>();
424             //TODO ShellCommandHelper ?
425             int result = CommandLineUtils.executeCommandLine( commandline, new StreamConsumer()
426             {
427                 public void consumeLine( String line )
428                 {
429                     cliOutput.add( line );
430                 }
431             }, new StreamConsumer()
432             {
433                 public void consumeLine( String line )
434                 {
435                     cliOutput.add( line );
436                 }
437             } );
438             if ( result != 0 )
439             {
440                 throw new InstallationException( "cli to get " + executable + " version return code " + result );
441             }
442             return cliOutput;
443         }
444         catch ( CommandLineException e )
445         {
446             log.error( "fail to execute " + executable + " with arg " + executorConfigurator.getVersionArgument() );
447             throw new InstallationException( e.getMessage(), e );
448         }
449     }
450 
451     private boolean alreadyExistInstallationName( Installation installation )
452         throws InstallationException
453     {
454         List<Installation> all = getAllInstallations();
455         for ( Installation install : all )
456         {
457             if ( org.apache.commons.lang.StringUtils.equals( installation.getName(), install.getName() ) &&
458                 ( installation.getInstallationId() == 0 ||
459                     installation.getInstallationId() != install.getInstallationId() ) )
460             {
461                 return true;
462             }
463         }
464         return false;
465     }
466 
467 }