View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.maven.plugin;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.util.ArrayList;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Locale;
27  
28  import org.apache.maven.artifact.Artifact;
29  import org.eclipse.jetty.util.IO;
30  import org.eclipse.jetty.util.log.Log;
31  import org.eclipse.jetty.util.log.Logger;
32  import org.eclipse.jetty.util.resource.Resource;
33  import org.eclipse.jetty.util.resource.ResourceCollection;
34  import org.eclipse.jetty.webapp.WebAppClassLoader;
35  import org.eclipse.jetty.webapp.WebAppContext;
36  import org.eclipse.jetty.webapp.WebInfConfiguration;
37  
38  
39  
40  /**
41   * MavenWebInfConfiguration
42   * 
43   * WebInfConfiguration to take account of overlaid wars expressed as project dependencies and
44   * potentiall configured via the maven-war-plugin.
45   *
46   */
47  public class MavenWebInfConfiguration extends WebInfConfiguration
48  {
49      private static final Logger LOG = Log.getLogger(WebInfConfiguration.class);
50  
51      
52      protected static int COUNTER = 0; 
53      protected Resource _originalResourceBase;
54      protected List<Resource>  _unpackedOverlayResources;
55    
56      
57      
58      
59      /** 
60       * @see org.eclipse.jetty.webapp.WebInfConfiguration#configure(org.eclipse.jetty.webapp.WebAppContext)
61       */
62      public void configure(WebAppContext context) throws Exception
63      {
64          JettyWebAppContext jwac = (JettyWebAppContext)context;
65          
66          //put the classes dir and all dependencies into the classpath
67          if (jwac.getClassPathFiles() != null)
68          {
69              if (LOG.isDebugEnabled()) LOG.debug("Setting up classpath ...");
70              Iterator itor = jwac.getClassPathFiles().iterator();
71              while (itor.hasNext())
72                  ((WebAppClassLoader)context.getClassLoader()).addClassPath(((File)itor.next()).getCanonicalPath());
73          }
74          
75          super.configure(context);
76          
77          // knock out environmental maven and plexus classes from webAppContext
78          String[] existingServerClasses = context.getServerClasses();
79          String[] newServerClasses = new String[2+(existingServerClasses==null?0:existingServerClasses.length)];
80          newServerClasses[0] = "org.apache.maven.";
81          newServerClasses[1] = "org.codehaus.plexus.";
82          System.arraycopy( existingServerClasses, 0, newServerClasses, 2, existingServerClasses.length );
83          if (LOG.isDebugEnabled())
84          {
85              LOG.debug("Server classes:");
86              for (int i=0;i<newServerClasses.length;i++)
87                  LOG.debug(newServerClasses[i]);
88          }
89          context.setServerClasses( newServerClasses ); 
90      }
91  
92      
93      
94  
95      /** 
96       * @see org.eclipse.jetty.webapp.WebInfConfiguration#preConfigure(org.eclipse.jetty.webapp.WebAppContext)
97       */
98      public void preConfigure(WebAppContext context) throws Exception
99      {
100         super.preConfigure(context);
101 
102     }
103     
104     
105     
106     
107     /** 
108      * @see org.eclipse.jetty.webapp.AbstractConfiguration#postConfigure(org.eclipse.jetty.webapp.WebAppContext)
109      */
110     public void postConfigure(WebAppContext context) throws Exception
111     {
112         super.postConfigure(context);
113     }
114 
115 
116     
117     
118     /** 
119      * @see org.eclipse.jetty.webapp.WebInfConfiguration#deconfigure(org.eclipse.jetty.webapp.WebAppContext)
120      */
121     public void deconfigure(WebAppContext context) throws Exception
122     {   
123         //remove the unpacked wars
124         if (_unpackedOverlayResources != null && !_unpackedOverlayResources.isEmpty())
125         {
126             try
127             {
128                 for (Resource r:_unpackedOverlayResources)
129                 {
130                     IO.delete(r.getFile());
131                 }
132             }
133             catch (IOException e)
134             {
135                 LOG.ignore(e);
136             }
137         }
138         super.deconfigure(context);
139         //restore whatever the base resource was before we might have included overlaid wars
140         context.setBaseResource(_originalResourceBase);
141     }
142 
143     
144     
145 
146     /** 
147      * @see org.eclipse.jetty.webapp.WebInfConfiguration#unpack(org.eclipse.jetty.webapp.WebAppContext)
148      */
149     @Override
150     public void unpack(WebAppContext context) throws IOException
151     {
152         //Unpack and find base resource as normal
153         super.unpack(context);
154         
155         //Get the base resource for the "virtual" webapp
156         _originalResourceBase = context.getBaseResource();
157 
158         JettyWebAppContext jwac = (JettyWebAppContext)context;
159 
160         //determine sequencing of overlays
161         _unpackedOverlayResources = new ArrayList<Resource>();
162 
163        
164 
165         if (jwac.getOverlays() != null && !jwac.getOverlays().isEmpty())
166         {
167             List<Resource> resourceBaseCollection = new ArrayList<Resource>();
168 
169             for (Overlay o:jwac.getOverlays())
170             {
171                 //can refer to the current project in list of overlays for ordering purposes
172                 if (o.getConfig() != null && o.getConfig().isCurrentProject())
173                 {
174                     resourceBaseCollection.add(_originalResourceBase); 
175                     continue;
176                 }
177 
178                 Resource unpacked = unpackOverlay(jwac,o);
179                 _unpackedOverlayResources.add(unpacked); //remember the unpacked overlays for later so we can delete the tmp files
180                 resourceBaseCollection.add(unpacked); //add in the selectively unpacked overlay in the correct order to the webapps resource base
181             }
182 
183             if (!resourceBaseCollection.contains(_originalResourceBase))
184             {
185                 if (jwac.getBaseAppFirst())
186                 {
187                     LOG.info("Adding virtual project first in resource base list");
188                     resourceBaseCollection.add(0, _originalResourceBase);
189                 }
190                 else
191                 {
192                     LOG.info("Adding virtual project last in resource base list");
193                     resourceBaseCollection.add(_originalResourceBase);
194                 }
195             }
196 
197             jwac.setBaseResource(new ResourceCollection(resourceBaseCollection.toArray(new Resource[resourceBaseCollection.size()])));
198         }
199     }
200 
201 
202     /**
203      * Get the jars to examine from the files from which we have
204      * synthesized the classpath. Note that the classpath is not
205      * set at this point, so we cannot get them from the classpath.
206      * @param context
207      * @return the list of jars found
208      */
209     @Override
210     protected List<Resource> findJars (WebAppContext context)
211     throws Exception
212     {
213         List<Resource> list = new ArrayList<Resource>();
214         JettyWebAppContext jwac = (JettyWebAppContext)context;
215         if (jwac.getClassPathFiles() != null)
216         {
217             for (File f: jwac.getClassPathFiles())
218             {
219                 if (f.getName().toLowerCase(Locale.ENGLISH).endsWith(".jar"))
220                 {
221                     try
222                     {
223                         list.add(Resource.newResource(f.toURI()));
224                     }
225                     catch (Exception e)
226                     {
227                         LOG.warn("Bad url ", e);
228                     }
229                 }
230             }
231         }
232 
233         List<Resource> superList = super.findJars(context);
234         if (superList != null)
235             list.addAll(superList);
236         return list;
237     }
238     
239     
240 
241     protected  Resource unpackOverlay (WebAppContext context, Overlay overlay)
242     throws IOException
243     {
244         LOG.info("Unpacking overlay: " + overlay);
245         
246         //resolve if not already resolved
247         resolveTempDirectory(context);
248         
249         if (overlay.getResource() == null)
250             return null; //nothing to unpack
251    
252         //Get the name of the overlayed war and unpack it to a dir of the
253         //same name in the temporary directory
254         String name = overlay.getResource().getName();
255         if (name.endsWith("!/"))
256             name = name.substring(0,name.length()-2);
257         int i = name.lastIndexOf('/');
258         if (i>0)
259             name = name.substring(i+1,name.length());
260         name = name.replace('.', '_');
261         name = name+(++COUNTER); //add some digits to ensure uniqueness
262         File dir = new File(context.getTempDirectory(), name); 
263         
264         //if specified targetPath, unpack to that subdir instead
265         File unpackDir = dir;
266         if (overlay.getConfig() != null && overlay.getConfig().getTargetPath() != null)
267             unpackDir = new File (dir, overlay.getConfig().getTargetPath());
268         
269         overlay.getResource().copyTo(unpackDir);
270         //use top level of unpacked content
271         Resource unpackedOverlay = Resource.newResource(dir.getCanonicalPath());
272         
273         LOG.info("Unpacked overlay: "+overlay+" to "+unpackedOverlay);
274         return  unpackedOverlay;
275     }
276     
277     protected Artifact getArtifactForOverlay (OverlayConfig o, List<Artifact> warArtifacts)
278     {
279         if (o == null || warArtifacts == null || warArtifacts.isEmpty())
280             return null;
281         
282         for (Artifact a:warArtifacts)
283         {
284             if (overlayMatchesArtifact (o, a))
285             {
286                return a;
287             }
288         }
289         
290         return null;
291     }
292     
293     protected boolean overlayMatchesArtifact(OverlayConfig o, Artifact a)
294     {
295         if ((o.getGroupId() == null && a.getGroupId() == null) || (o.getGroupId() != null && o.getGroupId().equals(a.getGroupId())))
296         {
297             if ((o.getArtifactId() == null && a.getArtifactId() == null) || (o.getArtifactId() != null && o.getArtifactId().equals(a.getArtifactId())))
298             {
299                 if ((o.getClassifier() == null) || (o.getClassifier().equals(a.getClassifier())))
300                     return true;
301             }
302         }
303         return false;
304     }
305 }