View Javadoc

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