/* * RHQ Management Platform * Copyright (C) 2005-2010 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2, as * published by the Free Software Foundation, and/or the GNU Lesser * General Public License, version 2.1, also as published by the Free * Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License and the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU General Public License * and the GNU Lesser General Public License along with this program; * if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.rhq.core.util.updater; import java.io.ByteArrayOutputStream; import java.util.regex.Pattern; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import org.rhq.core.template.TemplateEngine; import org.rhq.core.util.MessageDigestGenerator; import org.rhq.core.util.ZipUtil; import org.rhq.core.util.stream.StreamUtil; /** * A visitor object that will perform some in-memory work for each zip entry it visits. * * @author John Mazzitelli */ public class InMemoryZipFileVisitor implements ZipUtil.ZipEntryVisitor { private final FileHashcodeMap fileHashcodeMap = new FileHashcodeMap(); private final Pattern filesToRealizeRegex; private final TemplateEngine templateEngine; private final MessageDigestGenerator hashcodeGenerator; /** * Creates the visitor. When the visitor hits a zip entry whose name matches * filesToRealizeRegex, that zip entry will be realized via the template engine prior * to its hashcode being computed. In other words the file's hashcode will be computed * on the content after its replacement variables have been replaced. * If you just want this visitor to walk a zip file without realizing any files, pass in * a null pattern or pass in a null template engine. This will, in effect, * have this visitor collect all zip file entry names and calculate their hashcodes based on * all content within the zip file. * * @param filesToRealizeRegex pattern of files that are to be realized prior to hashcodes being computed * @param templateEngine the template engine that replaces replacement variables in files to be realized */ public InMemoryZipFileVisitor(Pattern filesToRealizeRegex, TemplateEngine templateEngine) { if (filesToRealizeRegex == null || templateEngine == null) { filesToRealizeRegex = null; templateEngine = null; } this.filesToRealizeRegex = filesToRealizeRegex; this.templateEngine = templateEngine; this.hashcodeGenerator = new MessageDigestGenerator(); } /** * Returns the file/hashcode data this visitor has collected. * @return map containing filenames (zip file entry names) and their hashcodes */ public FileHashcodeMap getFileHashcodeMap() { return fileHashcodeMap; } public boolean visit(ZipEntry entry, ZipInputStream stream) throws Exception { if (entry.isDirectory()) { return true; // skip directory entries, we only care about the files } String pathname = entry.getName(); String hashcode; if (this.filesToRealizeRegex != null && this.filesToRealizeRegex.matcher(pathname).matches()) { // this entry needs to be realized, do it now, then calc the hashcode // note: tempateEngine will never be null if we got here int contentSize = (int) entry.getSize(); ByteArrayOutputStream baos = new ByteArrayOutputStream((contentSize > 0) ? contentSize : 32768); StreamUtil.copy(stream, baos, false); String content = this.templateEngine.replaceTokens(baos.toString()); baos = null; hashcode = this.hashcodeGenerator.calcDigestString(content); } else { hashcode = this.hashcodeGenerator.calcDigestString(stream); } this.fileHashcodeMap.put(pathname, hashcode); return true; } }