001: /**
002: * Sequoia: Database clustering technology.
003: * Copyright (C) 2002-2004 French National Institute For Research In Computer
004: * Science And Control (INRIA).
005: * Contact: sequoia@continuent.org
006: *
007: * Licensed under the Apache License, Version 2.0 (the "License");
008: * you may not use this file except in compliance with the License.
009: * You may obtain a copy of the License at
010: *
011: * http://www.apache.org/licenses/LICENSE-2.0
012: *
013: * Unless required by applicable law or agreed to in writing, software
014: * distributed under the License is distributed on an "AS IS" BASIS,
015: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016: * See the License for the specific language governing permissions and
017: * limitations under the License.
018: *
019: * Initial developer(s): Emmanuel Cecchet
020: * Contributor(s): Nicolas Modrzyk
021: */package org.continuent.sequoia.controller.backup.backupers;
022:
023: import java.io.BufferedInputStream;
024: import java.io.BufferedOutputStream;
025: import java.io.File;
026: import java.io.FileInputStream;
027: import java.io.FileOutputStream;
028: import java.io.IOException;
029: import java.util.zip.ZipEntry;
030: import java.util.zip.ZipInputStream;
031: import java.util.zip.ZipOutputStream;
032:
033: import org.continuent.sequoia.common.i18n.Translate;
034: import org.continuent.sequoia.common.log.Trace;
035:
036: /**
037: * Zip utility class to compress a directory into a single zip file and
038: * vice-versa.
039: *
040: * @author <a href="mailto:emmanuel.cecchet@emicnetworks.com">Emmanuel Cecchet</a>
041: * @author <a href="mailto:Nicolas.Modrzyk@inrialpes.fr">Nicolas Modrzyk </a>
042: */
043: public class Zipper {
044: /** Extension for zipped file names */
045: public static final String ZIP_EXT = ".zip";
046:
047: private static final int BUFFER_SIZE = 2048;
048:
049: /** Store full path in zip when archiving */
050: public static final int STORE_FULL_PATH_IN_ZIP = 0;
051: /** Store only file names in zip when archiving */
052: public static final int STORE_NAME_ONLY_IN_ZIP = 1;
053: /** Store relative path in zip when archiving */
054: public static final int STORE_RELATIVE_PATH_IN_ZIP = 2;
055: /** Store path relative to root directory in zip when archiving */
056: public static final int STORE_PATH_FROM_ZIP_ROOT = 3;
057:
058: static Trace logger = Trace.getLogger(Zipper.class.getName());
059:
060: /**
061: * Create a zip file from directory
062: *
063: * @param zipName name of the file to create
064: * @param rootDir root directory to archive
065: * @param storePolicy the store policy to use (STORE_FULL_PATH_IN_ZIP,
066: * STORE_NAME_ONLY_IN_ZIP, STORE_RELATIVE_PATH_IN_ZIP or
067: * STORE_PATH_FROM_ZIP_ROOT)
068: * @throws Exception if fails
069: */
070: public static void zip(String zipName, String rootDir,
071: int storePolicy) throws Exception {
072: if (zipName == null || rootDir == null)
073: throw new Exception("Invalid arguments to create zip file");
074: try {
075: FileOutputStream fos = new FileOutputStream(zipName);
076: ZipOutputStream zos = new ZipOutputStream(fos);
077:
078: directoryWalker(rootDir, rootDir, zos, storePolicy);
079:
080: zos.flush();
081: zos.finish();
082: zos.close();
083: fos.close();
084: } catch (IOException e) {
085: logger.error(e.getMessage());
086: throw e;
087: }
088: }
089:
090: /**
091: * Expand the content of the zip file
092: *
093: * @param zipName of the file to expand
094: * @param targetDir where to place unzipped files
095: * @throws Exception if fails
096: */
097: public static void unzip(String zipName, String targetDir)
098: throws Exception {
099: File ftargetDir = new File(targetDir);
100: if (!ftargetDir.exists())
101: ftargetDir.mkdirs();
102: if (!ftargetDir.exists())
103: throw new Exception(Translate
104: .get("zip.invalid.target.directory"));
105:
106: File fzipname = new File(zipName);
107: if (!fzipname.exists())
108: throw new Exception(Translate.get(
109: "zip.invalid.source.file", zipName));
110:
111: try {
112: FileInputStream fis = new FileInputStream(fzipname);
113: ZipInputStream zis = new ZipInputStream(fis);
114:
115: ZipEntry entry;
116:
117: byte[] data = new byte[BUFFER_SIZE];
118: while ((entry = zis.getNextEntry()) != null) {
119: int count;
120: String target = targetDir + File.separator
121: + entry.getName();
122: File fget = new File(target);
123: fget.mkdirs(); // create needed new directories
124: fget.delete(); // delete directory but not parents
125: if (logger.isDebugEnabled())
126: logger.debug(Translate.get("zip.extracting",
127: new String[] { String.valueOf(entry),
128: fget.getAbsolutePath() }));
129: FileOutputStream fos = new FileOutputStream(target);
130:
131: BufferedOutputStream dest = new BufferedOutputStream(
132: fos, BUFFER_SIZE);
133: while ((count = zis.read(data, 0, BUFFER_SIZE)) != -1) {
134: dest.write(data, 0, count);
135: }
136: dest.flush();
137: dest.close();
138: }
139: zis.close();
140: } catch (Exception e) {
141: logger.error("Error while uncompressing archive", e);
142: throw e;
143: }
144: }
145:
146: /**
147: * Walk through currentDir and recursively in its subdirectories. Each file
148: * found is zipped.
149: *
150: * @param currentDir directory to walk through
151: * @param rootDir root directory for path references
152: * @param zos ZipOutputSteam to write to
153: * @param storePolicy file path storing policy
154: * @throws IOException if an error occurs
155: */
156: private static void directoryWalker(String currentDir,
157: String rootDir, ZipOutputStream zos, int storePolicy)
158: throws IOException {
159: File dirObj = new File(currentDir);
160: if (dirObj.exists() == true) {
161: if (dirObj.isDirectory() == true) {
162:
163: File[] fileList = dirObj.listFiles();
164:
165: for (int i = 0; i < fileList.length; i++) {
166: if (fileList[i].isDirectory()) {
167: directoryWalker(fileList[i].getPath(), rootDir,
168: zos, storePolicy);
169: } else if (fileList[i].isFile()) {
170: zipFile(fileList[i].getPath(), zos,
171: storePolicy, rootDir);
172: }
173: }
174: } else {
175: if (logger.isDebugEnabled())
176: logger.debug(Translate.get("zip.not.directory",
177: rootDir));
178: }
179: } else {
180: if (logger.isDebugEnabled())
181: logger.debug(Translate.get("zip.directory.not.found",
182: rootDir));
183: }
184: }
185:
186: /**
187: * TODO: zipFunc definition.
188: *
189: * @param filePath file to compress
190: * @param zos ZipOutputSteam to write to
191: * @param storePolicy file path storing policy
192: * @param rootDir root directory for path references
193: * @throws IOException if an error occurs
194: */
195: private static void zipFile(String filePath, ZipOutputStream zos,
196: int storePolicy, String rootDir) throws IOException {
197: File ffilePath = new File(filePath);
198: String path = "";
199: switch (storePolicy) {
200: case STORE_FULL_PATH_IN_ZIP:
201: path = ffilePath.getAbsolutePath();
202: break;
203: case STORE_NAME_ONLY_IN_ZIP:
204: ffilePath.getName();
205: break;
206: case STORE_RELATIVE_PATH_IN_ZIP:
207: File f = new File("");
208: String pathToHere = f.getAbsolutePath();
209: path = ffilePath.getAbsolutePath();
210: path = path.substring(path.indexOf(pathToHere
211: + File.separator)
212: + pathToHere.length());
213: break;
214: case STORE_PATH_FROM_ZIP_ROOT:
215: path = ffilePath.getAbsolutePath();
216: String tmpDir = rootDir + File.separator;
217: // Strip rootdir from absolute path
218: path = path.substring(path.indexOf(tmpDir)
219: + tmpDir.length());
220: break;
221: default:
222: break;
223: }
224:
225: if (logger.isDebugEnabled())
226: logger.debug(Translate.get("zip.archiving", new String[] {
227: filePath, path }));
228:
229: FileInputStream fileStream = new FileInputStream(filePath);
230: BufferedInputStream bis = new BufferedInputStream(fileStream);
231:
232: ZipEntry fileEntry = new ZipEntry(path);
233: zos.putNextEntry(fileEntry);
234:
235: byte[] data = new byte[BUFFER_SIZE];
236: int byteCount;
237: while ((byteCount = bis.read(data, 0, BUFFER_SIZE)) > -1)
238: zos.write(data, 0, byteCount);
239: }
240:
241: }
|