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.FileOutputStream;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.net.URL;
26  import java.util.Arrays;
27  import java.util.Collections;
28  import java.util.List;
29  import java.util.jar.JarEntry;
30  import java.util.jar.JarInputStream;
31  import java.util.jar.Manifest;
32  
33  import org.codehaus.plexus.util.SelectorUtils;
34  import org.eclipse.jetty.util.IO;
35  import org.eclipse.jetty.util.URIUtil;
36  import org.eclipse.jetty.util.log.Log;
37  import org.eclipse.jetty.util.log.Logger;
38  import org.eclipse.jetty.util.resource.JarResource;
39  
40  
41  
42  /**
43   * SelectiveJarResource
44   *
45   * Selectively copies resources from a jar file based on includes/excludes.
46   * 
47   */
48  public class SelectiveJarResource extends JarResource
49  {  
50      private static final Logger LOG = Log.getLogger(SelectiveJarResource.class);
51      public static final List<String> DEFAULT_INCLUDES = Arrays.asList(new String[]{"**"});// No includes supplied, so set it to 'matches all'
52      public static final List<String> DEFAULT_EXCLUDES = Collections.emptyList(); //No includes, set to no exclusions
53  
54  
55      List<String> _includes = null;
56      List<String> _excludes = null;
57      boolean _caseSensitive = false;
58      
59  
60      /**
61       * @param url
62       */
63      public SelectiveJarResource(URL url)
64      {
65          super(url);
66      }
67    
68      /**
69       * @param url
70       * @param useCaches
71       */
72      public SelectiveJarResource(URL url, boolean useCaches)
73      {
74          super(url, useCaches);
75      }
76      
77      
78      public void setCaseSensitive (boolean caseSensitive)
79      {
80          _caseSensitive = caseSensitive;
81      }
82      
83      public void setIncludes (List<String> patterns)
84      {
85          _includes = patterns;
86      }
87      
88      
89      public void setExcludes (List<String> patterns)
90      {
91          _excludes = patterns;
92      }
93      
94      
95      protected boolean isIncluded (String name)
96      {    
97          for (String include:_includes)
98          {
99              if (SelectorUtils.matchPath(include, name, _caseSensitive))
100             {
101                 return true;
102             }
103         }
104         return false;
105     }
106     
107     protected boolean isExcluded (String name)
108     {
109         for (String exclude:_excludes)
110         {
111             if (SelectorUtils.matchPath (exclude, name, _caseSensitive))
112             {
113                 return true;
114             }
115         }
116         return false;
117     }
118     
119     
120   
121 
122     /** 
123      * @see org.eclipse.jetty.util.resource.JarResource#copyTo(java.io.File)
124      */
125     @Override
126     public void copyTo(File directory) throws IOException
127     {
128         if (_includes == null)
129             _includes = DEFAULT_INCLUDES;
130         if (_excludes == null)
131             _excludes = DEFAULT_EXCLUDES;
132         
133         //Copy contents of the jar file to the given directory, 
134         //using the includes and excludes patterns to control which
135         //parts of the jar file are copied
136         if (!exists())
137             return;
138         
139         String urlString = this.getURL().toExternalForm().trim();
140         int endOfJarUrl = urlString.indexOf("!/");
141         int startOfJarUrl = (endOfJarUrl >= 0?4:0);
142         
143         if (endOfJarUrl < 0)
144             throw new IOException("Not a valid jar url: "+urlString);
145         
146         URL jarFileURL = new URL(urlString.substring(startOfJarUrl, endOfJarUrl));
147      
148         InputStream is = jarFileURL.openConnection().getInputStream();
149         JarInputStream jin = new JarInputStream(is);
150         JarEntry entry;
151 
152         while((entry=jin.getNextJarEntry())!=null)
153         {
154             String entryName = entry.getName();
155 
156             LOG.debug("Looking at "+entryName);
157             String dotCheck = entryName.replace('\\', '/');   
158             dotCheck = URIUtil.canonicalPath(dotCheck);
159             if (dotCheck == null)
160             {
161                 LOG.info("Invalid entry: "+entryName);
162                 continue;
163             }
164 
165             File file=new File(directory,entryName);
166 
167             if (entry.isDirectory())
168             {
169                 if (isIncluded(entryName))
170                 {
171                     if (!isExcluded(entryName))
172                     {
173                         // Make directory
174                         if (!file.exists())
175                             file.mkdirs();
176                     }
177                     else
178                         LOG.debug("{} dir is excluded", entryName);
179                 }
180                 else
181                     LOG.debug("{} dir is NOT included", entryName);
182             }
183             else
184             {
185                 //entry is a file, is it included?
186                 if (isIncluded(entryName))
187                 {
188                     if (!isExcluded(entryName))
189                     {
190                         // make directory (some jars don't list dirs)
191                         File dir = new File(file.getParent());
192                         if (!dir.exists())
193                             dir.mkdirs();
194 
195                         // Make file
196                         FileOutputStream fout = null;
197                         try
198                         {
199                             fout = new FileOutputStream(file);
200                             IO.copy(jin,fout);
201                         }
202                         finally
203                         {
204                             IO.close(fout);
205                         }
206 
207                         // touch the file.
208                         if (entry.getTime()>=0)
209                             file.setLastModified(entry.getTime());
210                     }
211                     else
212                         LOG.debug("{} file is excluded", entryName);
213                 }
214                 else
215                     LOG.debug("{} file is NOT included", entryName);
216             }
217         }
218         
219         Manifest manifest = jin.getManifest();
220         if (manifest != null)
221         {
222             if (isIncluded("META-INF") && !isExcluded("META-INF"))
223             {
224                 File metaInf = new File (directory, "META-INF");
225                 metaInf.mkdir();
226                 File f = new File(metaInf, "MANIFEST.MF");
227                 FileOutputStream fout = new FileOutputStream(f);
228                 manifest.write(fout);
229                 fout.close();   
230             }
231         }
232         IO.close(jin);
233     }
234     
235 }