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