View Javadoc

1   package org.apache.maven.it;
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.FileInputStream;
24  import java.io.FileOutputStream;
25  import java.io.IOException;
26  import java.io.InputStream;
27  import java.io.PrintStream;
28  import java.lang.reflect.Constructor;
29  import java.lang.reflect.InvocationTargetException;
30  import java.lang.reflect.Method;
31  import java.net.MalformedURLException;
32  import java.net.URL;
33  import java.net.URLClassLoader;
34  import java.util.ArrayList;
35  import java.util.List;
36  import java.util.Properties;
37  
38  /**
39   * Launches an embedded Maven 3.x instance from some Maven installation directory.
40   *
41   * @author Benjamin Bentmann
42   */
43  class Embedded3xLauncher
44      implements MavenLauncher
45  {
46  
47      private final Object mavenCli;
48  
49      private final Method doMain;
50  
51      public Embedded3xLauncher( String mavenHome )
52          throws LauncherException
53      {
54          if ( mavenHome == null || mavenHome.length() <= 0 )
55          {
56              throw new LauncherException( "Invalid Maven home directory " + mavenHome );
57          }
58  
59          System.setProperty( "maven.home", mavenHome );
60  
61          File config = new File( mavenHome, "bin/m2.conf" );
62  
63          ClassLoader bootLoader = getBootLoader( mavenHome );
64  
65          ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
66          Thread.currentThread().setContextClassLoader( bootLoader );
67          try
68          {
69              Class launcherClass = bootLoader.loadClass( "org.codehaus.plexus.classworlds.launcher.Launcher" );
70  
71              Object launcher = launcherClass.newInstance();
72  
73              Method configure = launcherClass.getMethod( "configure", new Class[]{ InputStream.class } );
74  
75              configure.invoke( launcher, new Object[]{ new FileInputStream( config ) } );
76  
77              Method getWorld = launcherClass.getMethod( "getWorld", null );
78              Object classWorld = getWorld.invoke( launcher, null );
79  
80              Method getMainClass = launcherClass.getMethod( "getMainClass", null );
81              Class cliClass = (Class) getMainClass.invoke( launcher, null );
82  
83              Constructor newMavenCli = cliClass.getConstructor( new Class[]{ classWorld.getClass() } );
84              mavenCli = newMavenCli.newInstance( new Object[]{ classWorld } );
85  
86              Class[] parameterTypes = { String[].class, String.class, PrintStream.class, PrintStream.class };
87              doMain = cliClass.getMethod( "doMain", parameterTypes );
88          }
89          catch ( ClassNotFoundException e )
90          {
91              throw new LauncherException( "Invalid Maven home directory " + mavenHome, e );
92          }
93          catch ( InstantiationException e )
94          {
95              throw new LauncherException( "Invalid Maven home directory " + mavenHome, e );
96          }
97          catch ( IllegalAccessException e )
98          {
99              throw new LauncherException( "Invalid Maven home directory " + mavenHome, e );
100         }
101         catch ( NoSuchMethodException e )
102         {
103             throw new LauncherException( "Invalid Maven home directory " + mavenHome, e );
104         }
105         catch ( InvocationTargetException e )
106         {
107             throw new LauncherException( "Invalid Maven home directory " + mavenHome, e );
108         }
109         catch ( IOException e )
110         {
111             throw new LauncherException( "Invalid Maven home directory " + mavenHome, e );
112         }
113         finally
114         {
115             Thread.currentThread().setContextClassLoader( oldClassLoader );
116         }
117     }
118 
119     private static ClassLoader getBootLoader( String mavenHome )
120     {
121         File bootDir = new File( mavenHome, "boot" );
122 
123         List urls = new ArrayList();
124 
125         addUrls( urls, bootDir );
126 
127         if ( urls.isEmpty() )
128         {
129             throw new IllegalArgumentException( "Invalid Maven home directory " + mavenHome );
130         }
131 
132         URL[] ucp = (URL[]) urls.toArray( new URL[urls.size()] );
133 
134         return new URLClassLoader( ucp, ClassLoader.getSystemClassLoader().getParent() );
135     }
136 
137     private static void addUrls( List urls, File directory )
138     {
139         File[] jars = directory.listFiles();
140 
141         if ( jars != null )
142         {
143             for ( int i = 0; i < jars.length; i++ )
144             {
145                 File jar = jars[i];
146 
147                 if ( jar.getName().endsWith( ".jar" ) )
148                 {
149                     try
150                     {
151                         urls.add( jar.toURI().toURL() );
152                     }
153                     catch ( MalformedURLException e )
154                     {
155                         throw (RuntimeException) new IllegalStateException().initCause( e );
156                     }
157                 }
158             }
159         }
160     }
161 
162     public int run( String[] cliArgs, String workingDirectory, File logFile )
163         throws IOException, LauncherException
164     {
165         PrintStream out = ( logFile != null ) ? new PrintStream( new FileOutputStream( logFile ) ) : System.out;
166         try
167         {
168             Properties originalProperties = System.getProperties();
169             System.setProperties( null );
170             System.setProperty( "maven.home", originalProperties.getProperty( "maven.home", "" ) );
171             System.setProperty( "user.dir", new File( workingDirectory ).getAbsolutePath() );
172 
173             ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
174             Thread.currentThread().setContextClassLoader( mavenCli.getClass().getClassLoader() );
175             try
176             {
177                 Object result = doMain.invoke( mavenCli, new Object[]{ cliArgs, workingDirectory, out, out } );
178 
179                 return ( (Number) result ).intValue();
180             }
181             finally
182             {
183                 Thread.currentThread().setContextClassLoader( originalClassLoader );
184 
185                 System.setProperties( originalProperties );
186             }
187         }
188         catch ( IllegalAccessException e )
189         {
190             throw new LauncherException( "Failed to run Maven: " + e.getMessage(), e );
191         }
192         catch ( InvocationTargetException e )
193         {
194             throw new LauncherException( "Failed to run Maven: " + e.getMessage(), e );
195         }
196         finally
197         {
198             if ( logFile != null )
199             {
200                 out.close();
201             }
202         }
203     }
204 
205 }