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() && _originalResourceBase.exists())
173                 {
174                     resourceBaseCollection.add(_originalResourceBase); 
175                     LOG.info("Adding virtual project to resource base list");
176                     continue;
177                 }
178 
179                 Resource unpacked = unpackOverlay(jwac,o);
180                 _unpackedOverlayResources.add(unpacked); //remember the unpacked overlays for later so we can delete the tmp files
181                 resourceBaseCollection.add(unpacked); //add in the selectively unpacked overlay in the correct order to the webapps resource base
182                 LOG.info("Adding "+unpacked+" to resource base list");
183             }
184 
185             if (!resourceBaseCollection.contains(_originalResourceBase) && _originalResourceBase.exists())
186             {
187                 if (jwac.getBaseAppFirst())
188                 {
189                     LOG.info("Adding virtual project first in resource base list");
190                     resourceBaseCollection.add(0, _originalResourceBase);
191                 }
192                 else
193                 {
194                     LOG.info("Adding virtual project last in resource base list");
195                     resourceBaseCollection.add(_originalResourceBase);
196                 }
197             }
198 
199             jwac.setBaseResource(new ResourceCollection(resourceBaseCollection.toArray(new Resource[resourceBaseCollection.size()])));
200         }
201     }
202 
203 
204     /**
205      * Get the jars to examine from the files from which we have
206      * synthesized the classpath. Note that the classpath is not
207      * set at this point, so we cannot get them from the classpath.
208      * @param context
209      * @return the list of jars found
210      */
211     @Override
212     protected List<Resource> findJars (WebAppContext context)
213     throws Exception
214     {
215         List<Resource> list = new ArrayList<Resource>();
216         JettyWebAppContext jwac = (JettyWebAppContext)context;
217         if (jwac.getClassPathFiles() != null)
218         {
219             for (File f: jwac.getClassPathFiles())
220             {
221                 if (f.getName().toLowerCase(Locale.ENGLISH).endsWith(".jar"))
222                 {
223                     try
224                     {
225                         list.add(Resource.newResource(f.toURI()));
226                     }
227                     catch (Exception e)
228                     {
229                         LOG.warn("Bad url ", e);
230                     }
231                 }
232             }
233         }
234 
235         List<Resource> superList = super.findJars(context);
236         if (superList != null)
237             list.addAll(superList);
238         return list;
239     }
240     
241     
242     
243     
244 
245     /** 
246      * Add in the classes dirs from test/classes and target/classes
247      * @see org.eclipse.jetty.webapp.WebInfConfiguration#findClassDirs(org.eclipse.jetty.webapp.WebAppContext)
248      */
249     @Override
250     protected List<Resource> findClassDirs(WebAppContext context) throws Exception
251     {
252         List<Resource> list = new ArrayList<Resource>();
253         
254         JettyWebAppContext jwac = (JettyWebAppContext)context;
255         if (jwac.getClassPathFiles() != null)
256         {
257             for (File f: jwac.getClassPathFiles())
258             {
259                 if (f.exists() && f.isDirectory())
260                 {
261                     try
262                     {
263                         list.add(Resource.newResource(f.toURI()));
264                     }
265                     catch (Exception e)
266                     {
267                         LOG.warn("Bad url ", e);
268                     }
269                 }
270             }
271         }
272         
273         List<Resource> classesDirs = super.findClassDirs(context);
274         if (classesDirs != null)
275             list.addAll(classesDirs);
276         return list;
277     }
278 
279 
280 
281 
282     protected  Resource unpackOverlay (WebAppContext context, Overlay overlay)
283     throws IOException
284     {
285         LOG.info("Unpacking overlay: " + overlay);
286         
287         //resolve if not already resolved
288         resolveTempDirectory(context);
289         
290         if (overlay.getResource() == null)
291             return null; //nothing to unpack
292    
293         //Get the name of the overlayed war and unpack it to a dir of the
294         //same name in the temporary directory
295         String name = overlay.getResource().getName();
296         if (name.endsWith("!/"))
297             name = name.substring(0,name.length()-2);
298         int i = name.lastIndexOf('/');
299         if (i>0)
300             name = name.substring(i+1,name.length());
301         name = name.replace('.', '_');
302         name = name+(++COUNTER); //add some digits to ensure uniqueness
303         File dir = new File(context.getTempDirectory(), name); 
304         
305         //if specified targetPath, unpack to that subdir instead
306         File unpackDir = dir;
307         if (overlay.getConfig() != null && overlay.getConfig().getTargetPath() != null)
308             unpackDir = new File (dir, overlay.getConfig().getTargetPath());
309         
310         overlay.getResource().copyTo(unpackDir);
311         //use top level of unpacked content
312         Resource unpackedOverlay = Resource.newResource(dir.getCanonicalPath());
313         
314         LOG.info("Unpacked overlay: "+overlay+" to "+unpackedOverlay);
315         return  unpackedOverlay;
316     }
317 }