View Javadoc

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