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().getCompileClasspathElements();
72              if ( classPathElements != null )
73              {
74                  for ( String classPathElement : classPathElements )
75                  {
76                      File classPathElementFile = new File( classPathElement );
77                      if ( classPathElementFile.exists() && 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                     if ( !isInProjectReferences( artifact, request.getMavenProject() ) )
117                     {
118                         String fileName = artifact.getFile().getName();
119                         if ( !fileInClassLoaderEntries.contains( fileName ) )
120                         {
121                             classLoaderEntries.add( artifact.getFile().toURI().toString() );
122                             fileInClassLoaderEntries.add( fileName );
123                         }
124                     }
125                     else
126                     {
127                         request.getLog().debug(
128                             "skip adding artifact " + artifact.getArtifactId() + " as it's in reactors" );
129                     }
130                 }
131 
132                 // in case of war dependency we must add /WEB-INF/lib/*.jar in entries and WEB-INF/classes
133                 if ( "war".equals( artifact.getType() ) && request.isAddWarDependenciesInClassloader() )
134                 {
135 
136                     File tmpDir = new File( tmpExtractDatas, artifact.getArtifactId() );
137 
138                     tmpDir.mkdirs();
139 
140                     tmpDirectories.add( tmpDir );
141 
142                     try
143                     {
144                         tmpDir.deleteOnExit();
145                         File warFile = artifact.getFile();
146                         UnArchiver unArchiver = archiverManager.getUnArchiver( "jar" );
147                         unArchiver.setSourceFile( warFile );
148                         unArchiver.setDestDirectory( tmpDir );
149                         unArchiver.extract();
150 
151                         File libsDirectory = new File( tmpDir, "WEB-INF/lib" );
152                         if ( libsDirectory.exists() )
153                         {
154                             String[] jars = libsDirectory.list( new FilenameFilter()
155                             {
156                                 public boolean accept( File file, String s )
157                                 {
158                                     return s.endsWith( ".jar" );
159                                 }
160                             } );
161                             for ( String jar : jars )
162                             {
163                                 File jarFile = new File( libsDirectory, jar );
164                                 if ( !fileInClassLoaderEntries.contains( jarFile.getName() ) )
165                                 {
166                                     classLoaderEntries.add( jarFile.toURI().toString() );
167                                     fileInClassLoaderEntries.add( jarFile.getName() );
168                                 }
169                                 else
170                                 {
171                                     request.getLog().debug( "skip adding file " + jarFile.getPath()
172                                                                 + " as it's already in classloader entries" );
173                                 }
174                             }
175                         }
176                         File classesDirectory = new File( tmpDir, "WEB-INF/classes" );
177                         if ( classesDirectory.exists() )
178                         {
179                             classLoaderEntries.add( classesDirectory.toURI().toString() );
180                         }
181                     }
182                     catch ( NoSuchArchiverException e )
183                     {
184                         throw new TomcatRunException( e.getMessage(), e );
185                     }
186                     catch ( ArchiverException e )
187                     {
188                         request.getLog().error(
189                             "fail to extract war file " + artifact.getFile() + ", reason:" + e.getMessage(), e );
190                         throw new TomcatRunException( e.getMessage(), e );
191                     }
192                 }
193             }
194         }
195 
196         return new ClassLoaderEntriesCalculatorResult( new ArrayList<String>( classLoaderEntries ), tmpDirectories );
197 
198     }
199 
200     private void deleteDirectory( File directory, Log log )
201         throws TomcatRunException
202     {
203         try
204         {
205             FileUtils.deleteDirectory( directory );
206         }
207         catch ( IOException e )
208         {
209             log.error( "fail to delete directory file " + directory + ", reason:" + e.getMessage(), e );
210             throw new TomcatRunException( e.getMessage(), e );
211         }
212     }
213 
214     protected boolean isInProjectReferences( Artifact artifact, MavenProject project )
215     {
216         if ( project.getProjectReferences() == null || project.getProjectReferences().isEmpty() )
217         {
218             return false;
219         }
220         @SuppressWarnings( "unchecked" ) Collection<MavenProject> mavenProjects =
221             project.getProjectReferences().values();
222         for ( MavenProject mavenProject : mavenProjects )
223         {
224             if ( StringUtils.equals( mavenProject.getId(), artifact.getId() ) )
225             {
226                 return true;
227             }
228         }
229         return false;
230     }
231 }