src/core/net/sf/basedb/util/extensions/manager/processor/ExtractResourcesProcessor.java

Code
Comments
Other
Rev Date Author Line
5601 01 Apr 11 nicklas 1 /**
5601 01 Apr 11 nicklas 2   $Id$
5601 01 Apr 11 nicklas 3
5601 01 Apr 11 nicklas 4   Copyright (C) 2011 Nicklas Nordborg
5601 01 Apr 11 nicklas 5
5601 01 Apr 11 nicklas 6   This file is part of BASE - BioArray Software Environment.
5601 01 Apr 11 nicklas 7   Available at http://base.thep.lu.se/
5601 01 Apr 11 nicklas 8
5601 01 Apr 11 nicklas 9   BASE is free software; you can redistribute it and/or
5601 01 Apr 11 nicklas 10   modify it under the terms of the GNU General Public License
5601 01 Apr 11 nicklas 11   as published by the Free Software Foundation; either version 3
5601 01 Apr 11 nicklas 12   of the License, or (at your option) any later version.
5601 01 Apr 11 nicklas 13
5601 01 Apr 11 nicklas 14   BASE is distributed in the hope that it will be useful,
5601 01 Apr 11 nicklas 15   but WITHOUT ANY WARRANTY; without even the implied warranty of
5601 01 Apr 11 nicklas 16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
5601 01 Apr 11 nicklas 17   GNU General Public License for more details.
5601 01 Apr 11 nicklas 18
5601 01 Apr 11 nicklas 19   You should have received a copy of the GNU General Public License
5601 01 Apr 11 nicklas 20   along with BASE. If not, see <http://www.gnu.org/licenses/>.
5601 01 Apr 11 nicklas 21 */
5603 08 Apr 11 nicklas 22 package net.sf.basedb.util.extensions.manager.processor;
5601 01 Apr 11 nicklas 23
5601 01 Apr 11 nicklas 24 import java.io.File;
5601 01 Apr 11 nicklas 25 import java.io.FileInputStream;
5601 01 Apr 11 nicklas 26 import java.io.FileNotFoundException;
5601 01 Apr 11 nicklas 27 import java.io.FileOutputStream;
5601 01 Apr 11 nicklas 28 import java.io.OutputStream;
5601 01 Apr 11 nicklas 29 import java.util.regex.Matcher;
5601 01 Apr 11 nicklas 30 import java.util.regex.Pattern;
5601 01 Apr 11 nicklas 31 import java.util.zip.ZipEntry;
5601 01 Apr 11 nicklas 32 import java.util.zip.ZipInputStream;
5601 01 Apr 11 nicklas 33
5601 01 Apr 11 nicklas 34 import net.sf.basedb.util.FileUtil;
5603 08 Apr 11 nicklas 35 import net.sf.basedb.util.extensions.manager.ExtensionsFile;
5603 08 Apr 11 nicklas 36 import net.sf.basedb.util.extensions.manager.ExtensionsFileProcessor;
5603 08 Apr 11 nicklas 37 import net.sf.basedb.util.extensions.manager.ExtensionsManager;
5603 08 Apr 11 nicklas 38 import net.sf.basedb.util.extensions.manager.ProcessResults;
5602 07 Apr 11 nicklas 39 import net.sf.basedb.util.extensions.manager.ExtensionsFile.WriteableExtensionsFile;
5603 08 Apr 11 nicklas 40 import net.sf.basedb.util.extensions.manager.filter.ValidAndNewOrModifiedFilter;
5601 01 Apr 11 nicklas 41
5601 01 Apr 11 nicklas 42 /**
5601 01 Apr 11 nicklas 43   A file processor implementation that extracts resources from JAR files.
5601 01 Apr 11 nicklas 44   The main target directory must be specified when an instance is constructed.
5601 01 Apr 11 nicklas 45   Each processed JAR file is extracted into a subdirectory with the same name
6021 19 Mar 12 nicklas 46   as the JAR file. Existing files are always overwritten.
5601 01 Apr 11 nicklas 47   <p>
5601 01 Apr 11 nicklas 48   
5601 01 Apr 11 nicklas 49   The filter (in the form of a regular expressions pattern) can be
5601 01 Apr 11 nicklas 50   specified to limit which files are extracted from the JAR file.
5601 01 Apr 11 nicklas 51   The filter is also used to re-write target file names if they
5601 01 Apr 11 nicklas 52   need to be different from the file names in the JAR file.
5603 08 Apr 11 nicklas 53   <p>
5603 08 Apr 11 nicklas 54   
5603 08 Apr 11 nicklas 55   Note! It is recommended that this processor is paired with a 
5603 08 Apr 11 nicklas 56   {@link ValidAndNewOrModifiedFilter} since it is usually no
5603 08 Apr 11 nicklas 57   point in extracting resources from invalid extensions.
5601 01 Apr 11 nicklas 58
5601 01 Apr 11 nicklas 59   @author Nicklas
5601 01 Apr 11 nicklas 60   @since 3.0
5601 01 Apr 11 nicklas 61   @base.modified $Date$
5601 01 Apr 11 nicklas 62 */
5601 01 Apr 11 nicklas 63 public class ExtractResourcesProcessor
5601 01 Apr 11 nicklas 64   implements ExtensionsFileProcessor
5601 01 Apr 11 nicklas 65 {
5601 01 Apr 11 nicklas 66
6444 09 Apr 14 nicklas 67   private static final org.slf4j.Logger log = 
6444 09 Apr 14 nicklas 68     org.slf4j.LoggerFactory.getLogger(ExtractResourcesProcessor.class);
5601 01 Apr 11 nicklas 69   
5601 01 Apr 11 nicklas 70   private final File mainDir;
5601 01 Apr 11 nicklas 71   private final Pattern filter;
5601 01 Apr 11 nicklas 72   private final String replacement;
5602 07 Apr 11 nicklas 73   private final ProcessResults results;
5601 01 Apr 11 nicklas 74   
5603 08 Apr 11 nicklas 75   private int numFiles;
5603 08 Apr 11 nicklas 76   private int numError;
5603 08 Apr 11 nicklas 77   private int numTotalExtracted;
5603 08 Apr 11 nicklas 78
5601 01 Apr 11 nicklas 79   /**
5601 01 Apr 11 nicklas 80     Create a new processor.
5601 01 Apr 11 nicklas 81     
5601 01 Apr 11 nicklas 82     @param mainDir The main directory to where the resources should be extracted
5601 01 Apr 11 nicklas 83   */
5605 12 Apr 11 nicklas 84   public ExtractResourcesProcessor(File mainDir, ProcessResults results)
5601 01 Apr 11 nicklas 85   {
5605 12 Apr 11 nicklas 86     this(mainDir, null, null, results);
5601 01 Apr 11 nicklas 87   }
5601 01 Apr 11 nicklas 88
5601 01 Apr 11 nicklas 89   /**
5601 01 Apr 11 nicklas 90     Create a new processor.
5601 01 Apr 11 nicklas 91     
5601 01 Apr 11 nicklas 92     @param mainDir The main directory to where the resources should be extracted
5601 01 Apr 11 nicklas 93     @param filter A regular expression filter that must match the file name
5601 01 Apr 11 nicklas 94       in the JAR file
5601 01 Apr 11 nicklas 95     @param replacement A replacement string to create a new file name
5601 01 Apr 11 nicklas 96       using {@link Matcher#replaceAll(String)}.
5601 01 Apr 11 nicklas 97   */
5605 12 Apr 11 nicklas 98   public ExtractResourcesProcessor(File mainDir, Pattern filter, String replacement, ProcessResults results)
5601 01 Apr 11 nicklas 99   {
5601 01 Apr 11 nicklas 100     this.mainDir = mainDir;
5601 01 Apr 11 nicklas 101     this.filter = filter;
5601 01 Apr 11 nicklas 102     this.replacement = replacement;
5602 07 Apr 11 nicklas 103     this.results = results;
5601 01 Apr 11 nicklas 104   }
5601 01 Apr 11 nicklas 105
5601 01 Apr 11 nicklas 106   
5601 01 Apr 11 nicklas 107   /*
5601 01 Apr 11 nicklas 108     From the ExtensionsFileProcessor interface
5601 01 Apr 11 nicklas 109     ------------------------------------------
5601 01 Apr 11 nicklas 110   */
5601 01 Apr 11 nicklas 111   @Override
5601 01 Apr 11 nicklas 112   public void begin(ExtensionsManager manager, int numFiles)
5603 08 Apr 11 nicklas 113   {
5603 08 Apr 11 nicklas 114     this.numFiles = 0;
5603 08 Apr 11 nicklas 115     this.numError = 0;
5603 08 Apr 11 nicklas 116     this.numTotalExtracted = 0;
5603 08 Apr 11 nicklas 117   }
5601 01 Apr 11 nicklas 118
5601 01 Apr 11 nicklas 119   @Override
5603 08 Apr 11 nicklas 120   public void processFile(ExtensionsManager manager, WriteableExtensionsFile wFile)
5601 01 Apr 11 nicklas 121   {
5603 08 Apr 11 nicklas 122     ExtensionsFile xtFile = wFile.getExtensionsFile();
5602 07 Apr 11 nicklas 123     if (!xtFile.isJar()) 
5602 07 Apr 11 nicklas 124     {
5603 08 Apr 11 nicklas 125       log.info("File is not a JAR file (skipping): " + xtFile);
5602 07 Apr 11 nicklas 126       return;
5602 07 Apr 11 nicklas 127     }
5603 08 Apr 11 nicklas 128
5602 07 Apr 11 nicklas 129     File jar = xtFile.getFile();
5601 01 Apr 11 nicklas 130     File targetDir = new File(mainDir, jar.getName());
5601 01 Apr 11 nicklas 131
5601 01 Apr 11 nicklas 132     log.info("Extracting resources from '" + jar.getName() + 
6021 19 Mar 12 nicklas 133         "' to " + targetDir);
5601 01 Apr 11 nicklas 134     log.debug("filter=" + filter + "; replacement=" + replacement);
5601 01 Apr 11 nicklas 135
5603 08 Apr 11 nicklas 136     ZipInputStream zipStream = null;
5601 01 Apr 11 nicklas 137     int numExtracted = 0;
5601 01 Apr 11 nicklas 138     try
5601 01 Apr 11 nicklas 139     {
5601 01 Apr 11 nicklas 140       zipStream = new ZipInputStream(new FileInputStream(jar));
5601 01 Apr 11 nicklas 141       ZipEntry zipEntry = null;
5601 01 Apr 11 nicklas 142       while ((zipEntry = zipStream.getNextEntry()) != null)
5601 01 Apr 11 nicklas 143       {
5601 01 Apr 11 nicklas 144         // Get the name of the zipped file, but strip first slash
5601 01 Apr 11 nicklas 145         String name = zipEntry.getName();
5601 01 Apr 11 nicklas 146         if (name.startsWith("/")) name = name.substring(1);
5601 01 Apr 11 nicklas 147
5602 07 Apr 11 nicklas 148         // Should the current entry be extracted or not? We start by assuming so ...
5601 01 Apr 11 nicklas 149         boolean extract = true;
5601 01 Apr 11 nicklas 150         // A filter may change the actual name of the extracted file
5601 01 Apr 11 nicklas 151         String extractionName = name;
5601 01 Apr 11 nicklas 152         if (zipEntry.isDirectory()) 
5601 01 Apr 11 nicklas 153         {
5601 01 Apr 11 nicklas 154           // Ignore directories
5601 01 Apr 11 nicklas 155           extract = false;
5602 07 Apr 11 nicklas 156           log.debug("Jar entry '" + name + "' is a directory (ignored).");
5601 01 Apr 11 nicklas 157         }
5601 01 Apr 11 nicklas 158         else if (filter != null)
5601 01 Apr 11 nicklas 159         {
5601 01 Apr 11 nicklas 160           // Ignore files not matched by the filter
5601 01 Apr 11 nicklas 161           Matcher matcher = filter.matcher(name);
5601 01 Apr 11 nicklas 162           if (!matcher.matches())
5601 01 Apr 11 nicklas 163           {
5601 01 Apr 11 nicklas 164             extract = false;
5602 07 Apr 11 nicklas 165             log.debug("Jar entry '" + name + "' doesn't match filter (ignored).");
5601 01 Apr 11 nicklas 166           }
5601 01 Apr 11 nicklas 167           else
5601 01 Apr 11 nicklas 168           {
5601 01 Apr 11 nicklas 169             extractionName = matcher.replaceAll(replacement);
5601 01 Apr 11 nicklas 170           }
5601 01 Apr 11 nicklas 171         }
5601 01 Apr 11 nicklas 172         
5601 01 Apr 11 nicklas 173         File targetFile = new File(targetDir, extractionName);
5601 01 Apr 11 nicklas 174         
5601 01 Apr 11 nicklas 175         // Now... it is finally time to extract the file
5601 01 Apr 11 nicklas 176         if (extract)
5601 01 Apr 11 nicklas 177         {
5601 01 Apr 11 nicklas 178           log.debug("Extracting '" + name + "' to " + targetFile);
5601 01 Apr 11 nicklas 179           File dir = targetFile.getParentFile();
5601 01 Apr 11 nicklas 180           dir.mkdirs();
5601 01 Apr 11 nicklas 181           if (!dir.exists())
5601 01 Apr 11 nicklas 182           {
5601 01 Apr 11 nicklas 183             throw new FileNotFoundException("Failed to create directory: " + dir);
5601 01 Apr 11 nicklas 184           }
5601 01 Apr 11 nicklas 185           OutputStream out = null;
5601 01 Apr 11 nicklas 186           try
5601 01 Apr 11 nicklas 187           {
5601 01 Apr 11 nicklas 188             out = new FileOutputStream(targetFile);
5601 01 Apr 11 nicklas 189             FileUtil.copy(zipStream, out);
5601 01 Apr 11 nicklas 190             out.close();
5601 01 Apr 11 nicklas 191           }
5601 01 Apr 11 nicklas 192           finally
5601 01 Apr 11 nicklas 193           {
5601 01 Apr 11 nicklas 194             FileUtil.close(out);
5601 01 Apr 11 nicklas 195           }
5601 01 Apr 11 nicklas 196           numExtracted++;
6021 19 Mar 12 nicklas 197           // Always set current time to force Tomcat to re-compile JSP files
6021 19 Mar 12 nicklas 198           if (!targetFile.setLastModified(System.currentTimeMillis()))
5601 01 Apr 11 nicklas 199           {
5601 01 Apr 11 nicklas 200             log.warn("Could not set last modification time on file: " + targetFile);
5601 01 Apr 11 nicklas 201           }
5601 01 Apr 11 nicklas 202           else
5601 01 Apr 11 nicklas 203           {
5601 01 Apr 11 nicklas 204             log.info("Extracted file '" + name + "' to " + targetFile);
5601 01 Apr 11 nicklas 205           }
5601 01 Apr 11 nicklas 206         }
5601 01 Apr 11 nicklas 207       }
5603 08 Apr 11 nicklas 208       numFiles++;
5603 08 Apr 11 nicklas 209       numTotalExtracted += numExtracted;
5603 08 Apr 11 nicklas 210       if (numExtracted > 0 && results != null)
5603 08 Apr 11 nicklas 211       {
5603 08 Apr 11 nicklas 212         results.addMessage(xtFile,  numExtracted + " resource(s) extracted successfully.");
5603 08 Apr 11 nicklas 213       }
5602 07 Apr 11 nicklas 214       log.info("Extracted " + numExtracted + " resources from '" + jar.getName() + "' to " + targetDir);
5601 01 Apr 11 nicklas 215     }
6379 13 Dec 13 nicklas 216     catch (Throwable ex)
5601 01 Apr 11 nicklas 217     {
5603 08 Apr 11 nicklas 218       wFile.setError(true);
5603 08 Apr 11 nicklas 219       numError++;
5603 08 Apr 11 nicklas 220       if (results != null)
5603 08 Apr 11 nicklas 221       {
6379 13 Dec 13 nicklas 222         results.addErrorMessage(xtFile, "Failed to extract resources: " + ex.getClass().getName() + "; " + ex.getMessage());
5603 08 Apr 11 nicklas 223       }
5603 08 Apr 11 nicklas 224       log.error("Failed to extract resources to directory: " + targetDir, ex);
5601 01 Apr 11 nicklas 225     }
5601 01 Apr 11 nicklas 226     finally
5601 01 Apr 11 nicklas 227     {
5601 01 Apr 11 nicklas 228       FileUtil.close(zipStream);
5601 01 Apr 11 nicklas 229     }
5601 01 Apr 11 nicklas 230   }
5601 01 Apr 11 nicklas 231   
5601 01 Apr 11 nicklas 232   @Override
5601 01 Apr 11 nicklas 233   public void done(ExtensionsManager manager)
5601 01 Apr 11 nicklas 234   {}
5602 07 Apr 11 nicklas 235   
5601 01 Apr 11 nicklas 236   @Override
5601 01 Apr 11 nicklas 237   public void done(ExtensionsManager manager, Throwable t)
5601 01 Apr 11 nicklas 238   {}
5601 01 Apr 11 nicklas 239   // ---------------------------------------------------
5603 08 Apr 11 nicklas 240   
5603 08 Apr 11 nicklas 241   /**
5603 08 Apr 11 nicklas 242     Get the number of files that was successfully processed.
5603 08 Apr 11 nicklas 243   */
5603 08 Apr 11 nicklas 244   public int getNumFiles()
5603 08 Apr 11 nicklas 245   {
5603 08 Apr 11 nicklas 246     return numFiles;
5603 08 Apr 11 nicklas 247   }
5603 08 Apr 11 nicklas 248   
5603 08 Apr 11 nicklas 249   /**
5603 08 Apr 11 nicklas 250     Get the number of files that was had an error.
5603 08 Apr 11 nicklas 251   */
5603 08 Apr 11 nicklas 252   public int getNumError()
5603 08 Apr 11 nicklas 253   {
5603 08 Apr 11 nicklas 254     return numError;
5603 08 Apr 11 nicklas 255   }
5603 08 Apr 11 nicklas 256   
5603 08 Apr 11 nicklas 257   /**
5603 08 Apr 11 nicklas 258     Get the total number of resources that was extracts.
5603 08 Apr 11 nicklas 259   */
5603 08 Apr 11 nicklas 260   public int getNumExtracted()
5603 08 Apr 11 nicklas 261   {
5603 08 Apr 11 nicklas 262     return numTotalExtracted;
5603 08 Apr 11 nicklas 263   }
5603 08 Apr 11 nicklas 264
5603 08 Apr 11 nicklas 265   
5601 01 Apr 11 nicklas 266 }