View Javadoc

1   package org.apache.tomcat.maven.common.run;
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.commons.io.FileUtils;
23  import org.apache.maven.artifact.Artifact;
24  import org.apache.maven.artifact.DependencyResolutionRequiredException;
25  import org.apache.maven.plugin.logging.Log;
26  import org.apache.maven.project.MavenProject;
27  import org.codehaus.plexus.archiver.ArchiverException;
28  import org.codehaus.plexus.archiver.UnArchiver;
29  import org.codehaus.plexus.archiver.manager.ArchiverManager;
30  import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
31  import org.codehaus.plexus.component.annotations.Component;
32  import org.codehaus.plexus.component.annotations.Requirement;
33  import org.codehaus.plexus.util.StringUtils;
34  
35  import java.io.File;
36  import java.io.FilenameFilter;
37  import java.io.IOException;
38  import java.util.ArrayList;
39  import java.util.Collection;
40  import java.util.LinkedHashSet;
41  import java.util.List;
42  import java.util.Set;
43  
44  /**
45   * @author Olivier Lamy
46   * @since 2.0
47   */
48  @Component (role = ClassLoaderEntriesCalculator.class)
49  public class DefaultClassLoaderEntriesCalculator
50      implements ClassLoaderEntriesCalculator
51  {
52  
53      @Requirement
54      private ArchiverManager archiverManager;
55  
56  
57      public ClassLoaderEntriesCalculatorResult calculateClassPathEntries( ClassLoaderEntriesCalculatorRequest request )
58          throws TomcatRunException
59      {
60          Set<String> classLoaderEntries = new LinkedHashSet<String>();
61  
62          List<String> fileInClassLoaderEntries = new ArrayList<String>();
63  
64          List<File> tmpDirectories = new ArrayList<File>();
65  
66          // add classes directories to loader
67          try
68          {
69              @SuppressWarnings ("unchecked") List<String> classPathElements = request.isUseTestClassPath()
70                  ? request.getMavenProject().getTestClasspathElements()
71                  : request.getMavenProject().getRuntimeClasspathElements();//.getCompileClasspathElements();
72              if ( classPathElements != null )
73              {
74                  for ( String classPathElement : classPathElements )
75                  {
76                      File classPathElementFile = new File( classPathElement );
77                      if ( classPathElementFile.isDirectory() )
78                      {
79                          request.getLog().debug(
80                              "adding classPathElementFile " + classPathElementFile.toURI().toString() );
81                          classLoaderEntries.add( classPathElementFile.toURI().toString() );
82                      }
83                  }
84              }
85          }
86          catch ( DependencyResolutionRequiredException e )
87          {
88              throw new TomcatRunException( e.getMessage(), e );
89          }
90  
91          // TODO find a solution to use a timestamp marker to not delete/extract all the time
92  
93          File tmpExtractDatas =
94              new File( request.getMavenProject().getBuild().getDirectory(), "apache-tomcat-maven-plugin" );
95  
96          if ( tmpExtractDatas.exists() )
97          {
98              deleteDirectory( tmpExtractDatas, request.getLog() );
99          }
100         tmpExtractDatas.mkdirs();
101 
102         // add artifacts to loader
103         if ( request.getDependencies() != null )
104         {
105             for ( Artifact artifact : request.getDependencies() )
106             {
107                 String scope = artifact.getScope();
108 
109                 // skip provided and test scoped artifacts
110                 if ( !Artifact.SCOPE_PROVIDED.equals( scope ) && ( !Artifact.SCOPE_TEST.equals( scope )
111                     || request.isUseTestClassPath() ) )
112                 {
113                     request.getLog().debug(
114                         "add dependency to webapploader " + artifact.getGroupId() + ":" + artifact.getArtifactId() + ":"
115                             + artifact.getVersion() + ":" + artifact.getScope() );
116                     // we add artifact dependencies and projects from reactor if file (ie jar) as users can go to install/package phase
117                     // so artifact.getFile is a file not a directory and not added when iterate on project.classPathElements
118                     if ( !isInProjectReferences( artifact, request.getMavenProject() ) ||  artifact.getFile().isFile() )
119                     {
120                         String fileName = artifact.getFile().getName();
121                         if ( !fileInClassLoaderEntries.contains( fileName ) )
122                         {
123                             classLoaderEntries.add( artifact.getFile().toURI().toString() );
124                             fileInClassLoaderEntries.add( fileName );
125                         }
126                     }
127                     else
128                     {
129                         request.getLog().debug(
130                             "skip adding artifact " + artifact.getArtifactId() + " as it's in reactors" );
131 
132                     }
133                 }
134 
135                 // in case of war dependency we must add /WEB-INF/lib/*.jar in entries and WEB-INF/classes
136                 if ( "war".equals( artifact.getType() ) && request.isAddWarDependenciesInClassloader() )
137                 {
138 
139                     File tmpDir = new File( tmpExtractDatas, artifact.getArtifactId() );
140 
141                     tmpDir.mkdirs();
142 
143                     tmpDirectories.add( tmpDir );
144 
145                     try
146                     {
147                         tmpDir.deleteOnExit();
148                         File warFile = artifact.getFile();
149                         UnArchiver unArchiver = archiverManager.getUnArchiver( "jar" );
150                         unArchiver.setSourceFile( warFile );
151                         unArchiver.setDestDirectory( tmpDir );
152                         unArchiver.extract();
153 
154                         File libsDirectory = new File( tmpDir, "WEB-INF/lib" );
155                         if ( libsDirectory.exists() )
156                         {
157                             String[] jars = libsDirectory.list( new FilenameFilter()
158                             {
159                                 public boolean accept( File file, String s )
160                                 {
161                                     return s.endsWith( ".jar" );
162                                 }
163                             } );
164                             for ( String jar : jars )
165                             {
166                                 File jarFile = new File( libsDirectory, jar );
167                                 if ( !fileInClassLoaderEntries.contains( jarFile.getName() ) )
168                                 {
169                                     classLoaderEntries.add( jarFile.toURI().toString() );
170                                     fileInClassLoaderEntries.add( jarFile.getName() );
171                                 }
172                                 else
173                                 {
174                                     request.getLog().debug( "skip adding file " + jarFile.getPath()
175                                                                 + " as it's already in classloader entries" );
176                                 }
177                             }
178                         }
179                         File classesDirectory = new File( tmpDir, "WEB-INF/classes" );
180                         if ( classesDirectory.exists() )
181                         {
182                             classLoaderEntries.add( classesDirectory.toURI().toString() );
183                         }
184                     }
185                     catch ( NoSuchArchiverException e )
186                     {
187                         throw new TomcatRunException( e.getMessage(), e );
188                     }
189                     catch ( ArchiverException e )
190                     {
191                         request.getLog().error(
192                             "fail to extract war file " + artifact.getFile() + ", reason:" + e.getMessage(), e );
193                         throw new TomcatRunException( e.getMessage(), e );
194                     }
195                 }
196             }
197         }
198 
199         return new ClassLoaderEntriesCalculatorResult( new ArrayList<String>( classLoaderEntries ), tmpDirectories );
200 
201     }
202 
203     private void deleteDirectory( File directory, Log log )
204         throws TomcatRunException
205     {
206         try
207         {
208             FileUtils.deleteDirectory( directory );
209         }
210         catch ( IOException e )
211         {
212             log.error( "fail to delete directory file " + directory + ", reason:" + e.getMessage(), e );
213             throw new TomcatRunException( e.getMessage(), e );
214         }
215     }
216 
217     protected boolean isInProjectReferences( Artifact artifact, MavenProject project )
218     {
219         if ( project.getProjectReferences() == null || project.getProjectReferences().isEmpty() )
220         {
221             return false;
222         }
223         @SuppressWarnings ("unchecked") Collection<MavenProject> mavenProjects =
224             project.getProjectReferences().values();
225         for ( MavenProject mavenProject : mavenProjects )
226         {
227             if ( StringUtils.equals( mavenProject.getId(), artifact.getId() ) )
228             {
229                 return true;
230             }
231         }
232         return false;
233     }
234 }