001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.internal.wizards.datatransfer;
011:
012: import java.io.IOException;
013: import java.lang.reflect.InvocationTargetException;
014: import java.util.ArrayList;
015: import java.util.Iterator;
016: import java.util.List;
017:
018: import org.eclipse.core.resources.IContainer;
019: import org.eclipse.core.resources.IFile;
020: import org.eclipse.core.resources.IResource;
021: import org.eclipse.core.runtime.CoreException;
022: import org.eclipse.core.runtime.IPath;
023: import org.eclipse.core.runtime.IProgressMonitor;
024: import org.eclipse.core.runtime.IStatus;
025: import org.eclipse.core.runtime.MultiStatus;
026: import org.eclipse.core.runtime.Status;
027: import org.eclipse.jface.operation.IRunnableWithProgress;
028: import org.eclipse.jface.operation.ModalContext;
029: import org.eclipse.osgi.util.NLS;
030: import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
031:
032: /**
033: * Operation for exporting a resource and its children to a new .zip or
034: * .tar.gz file.
035: *
036: * @since 3.1
037: */
038: public class ArchiveFileExportOperation implements
039: IRunnableWithProgress {
040: private IFileExporter exporter;
041:
042: private String destinationFilename;
043:
044: private IProgressMonitor monitor;
045:
046: private List resourcesToExport;
047:
048: private IResource resource;
049:
050: private List errorTable = new ArrayList(1); //IStatus
051:
052: private boolean useCompression = true;
053:
054: private boolean useTarFormat = false;
055:
056: private boolean createLeadupStructure = true;
057:
058: /**
059: * Create an instance of this class. Use this constructor if you wish to
060: * export specific resources without a common parent resource
061: *
062: * @param resources java.util.Vector
063: * @param filename java.lang.String
064: */
065: public ArchiveFileExportOperation(List resources, String filename) {
066: super ();
067:
068: // Eliminate redundancies in list of resources being exported
069: Iterator elementsEnum = resources.iterator();
070: while (elementsEnum.hasNext()) {
071: IResource currentResource = (IResource) elementsEnum.next();
072: if (isDescendent(resources, currentResource)) {
073: elementsEnum.remove(); //Removes currentResource;
074: }
075: }
076:
077: resourcesToExport = resources;
078: destinationFilename = filename;
079: }
080:
081: /**
082: * Create an instance of this class. Use this constructor if you wish
083: * to recursively export a single resource.
084: *
085: * @param res org.eclipse.core.resources.IResource;
086: * @param filename java.lang.String
087: */
088: public ArchiveFileExportOperation(IResource res, String filename) {
089: super ();
090: resource = res;
091: destinationFilename = filename;
092: }
093:
094: /**
095: * Create an instance of this class. Use this constructor if you wish to
096: * export specific resources with a common parent resource (affects container
097: * directory creation)
098: *
099: * @param res org.eclipse.core.resources.IResource
100: * @param resources java.util.Vector
101: * @param filename java.lang.String
102: */
103: public ArchiveFileExportOperation(IResource res, List resources,
104: String filename) {
105: this (res, filename);
106: resourcesToExport = resources;
107: }
108:
109: /**
110: * Add a new entry to the error table with the passed information
111: */
112: protected void addError(String message, Throwable e) {
113: errorTable.add(new Status(IStatus.ERROR,
114: IDEWorkbenchPlugin.IDE_WORKBENCH, 0, message, e));
115: }
116:
117: /**
118: * Answer the total number of file resources that exist at or below self
119: * in the resources hierarchy.
120: *
121: * @return int
122: * @param checkResource org.eclipse.core.resources.IResource
123: */
124: protected int countChildrenOf(IResource checkResource)
125: throws CoreException {
126: if (checkResource.getType() == IResource.FILE) {
127: return 1;
128: }
129:
130: int count = 0;
131: if (checkResource.isAccessible()) {
132: IResource[] children = ((IContainer) checkResource)
133: .members();
134: for (int i = 0; i < children.length; i++) {
135: count += countChildrenOf(children[i]);
136: }
137: }
138:
139: return count;
140: }
141:
142: /**
143: * Answer a boolean indicating the number of file resources that were
144: * specified for export
145: *
146: * @return int
147: */
148: protected int countSelectedResources() throws CoreException {
149: int result = 0;
150: Iterator resources = resourcesToExport.iterator();
151: while (resources.hasNext()) {
152: result += countChildrenOf((IResource) resources.next());
153: }
154:
155: return result;
156: }
157:
158: /**
159: * Export the passed resource to the destination .zip. Export with
160: * no path leadup
161: *
162: * @param exportResource org.eclipse.core.resources.IResource
163: */
164: protected void exportResource(IResource exportResource)
165: throws InterruptedException {
166: exportResource(exportResource, 1);
167: }
168:
169: /**
170: * Export the passed resource to the destination .zip
171: *
172: * @param exportResource org.eclipse.core.resources.IResource
173: * @param leadupDepth the number of resource levels to be included in
174: * the path including the resourse itself.
175: */
176: protected void exportResource(IResource exportResource,
177: int leadupDepth) throws InterruptedException {
178: if (!exportResource.isAccessible()) {
179: return;
180: }
181:
182: if (exportResource.getType() == IResource.FILE) {
183: String destinationName;
184: IPath fullPath = exportResource.getFullPath();
185: if (createLeadupStructure) {
186: destinationName = fullPath.makeRelative().toString();
187: } else {
188: destinationName = fullPath.removeFirstSegments(
189: fullPath.segmentCount() - leadupDepth)
190: .toString();
191: }
192: monitor.subTask(destinationName);
193:
194: try {
195: exporter.write((IFile) exportResource, destinationName);
196: } catch (IOException e) {
197: addError(
198: NLS
199: .bind(
200: DataTransferMessages.DataTransfer_errorExporting,
201: exportResource.getFullPath()
202: .makeRelative(), e
203: .getMessage()), e);
204: } catch (CoreException e) {
205: addError(
206: NLS
207: .bind(
208: DataTransferMessages.DataTransfer_errorExporting,
209: exportResource.getFullPath()
210: .makeRelative(), e
211: .getMessage()), e);
212: }
213:
214: monitor.worked(1);
215: ModalContext.checkCanceled(monitor);
216: } else {
217: IResource[] children = null;
218:
219: try {
220: children = ((IContainer) exportResource).members();
221: } catch (CoreException e) {
222: // this should never happen because an #isAccessible check is done before #members is invoked
223: addError(
224: NLS
225: .bind(
226: DataTransferMessages.DataTransfer_errorExporting,
227: exportResource.getFullPath()),
228: e);
229: }
230:
231: for (int i = 0; i < children.length; i++) {
232: exportResource(children[i], leadupDepth + 1);
233: }
234:
235: }
236: }
237:
238: /**
239: * Export the resources contained in the previously-defined
240: * resourcesToExport collection
241: */
242: protected void exportSpecifiedResources()
243: throws InterruptedException {
244: Iterator resources = resourcesToExport.iterator();
245:
246: while (resources.hasNext()) {
247: IResource currentResource = (IResource) resources.next();
248: exportResource(currentResource);
249: }
250: }
251:
252: /**
253: * Returns the status of the operation.
254: * If there were any errors, the result is a status object containing
255: * individual status objects for each error.
256: * If there were no errors, the result is a status object with error code <code>OK</code>.
257: *
258: * @return the status
259: */
260: public IStatus getStatus() {
261: IStatus[] errors = new IStatus[errorTable.size()];
262: errorTable.toArray(errors);
263: return new MultiStatus(
264: IDEWorkbenchPlugin.IDE_WORKBENCH,
265: IStatus.OK,
266: errors,
267: DataTransferMessages.FileSystemExportOperation_problemsExporting,
268: null);
269: }
270:
271: /**
272: * Initialize this operation
273: *
274: * @exception java.io.IOException
275: */
276: protected void initialize() throws IOException {
277: if (useTarFormat) {
278: exporter = new TarFileExporter(destinationFilename,
279: useCompression);
280: } else {
281: exporter = new ZipFileExporter(destinationFilename,
282: useCompression);
283: }
284: }
285:
286: /**
287: * Answer a boolean indicating whether the passed child is a descendent
288: * of one or more members of the passed resources collection
289: *
290: * @return boolean
291: * @param resources java.util.Vector
292: * @param child org.eclipse.core.resources.IResource
293: */
294: protected boolean isDescendent(List resources, IResource child) {
295: if (child.getType() == IResource.PROJECT) {
296: return false;
297: }
298:
299: IResource parent = child.getParent();
300: if (resources.contains(parent)) {
301: return true;
302: }
303:
304: return isDescendent(resources, parent);
305: }
306:
307: /**
308: * Export the resources that were previously specified for export
309: * (or if a single resource was specified then export it recursively)
310: */
311: public void run(IProgressMonitor progressMonitor)
312: throws InvocationTargetException, InterruptedException {
313: this .monitor = progressMonitor;
314:
315: try {
316: initialize();
317: } catch (IOException e) {
318: throw new InvocationTargetException(e, NLS.bind(
319: DataTransferMessages.ZipExport_cannotOpen, e
320: .getMessage()));
321: }
322:
323: try {
324: // ie.- a single resource for recursive export was specified
325: int totalWork = IProgressMonitor.UNKNOWN;
326: try {
327: if (resourcesToExport == null) {
328: totalWork = countChildrenOf(resource);
329: } else {
330: totalWork = countSelectedResources();
331: }
332: } catch (CoreException e) {
333: // Should not happen
334: }
335: monitor.beginTask(
336: DataTransferMessages.DataTransfer_exportingTitle,
337: totalWork);
338: if (resourcesToExport == null) {
339: exportResource(resource);
340: } else {
341: // ie.- a list of specific resources to export was specified
342: exportSpecifiedResources();
343: }
344:
345: try {
346: exporter.finished();
347: } catch (IOException e) {
348: throw new InvocationTargetException(e, NLS.bind(
349: DataTransferMessages.ZipExport_cannotClose, e
350: .getMessage()));
351: }
352: } finally {
353: monitor.done();
354: }
355: }
356:
357: /**
358: * Set this boolean indicating whether each exported resource's path should
359: * include containment hierarchies as dictated by its parents
360: *
361: * @param value boolean
362: */
363: public void setCreateLeadupStructure(boolean value) {
364: createLeadupStructure = value;
365: }
366:
367: /**
368: * Set this boolean indicating whether exported resources should
369: * be compressed (as opposed to simply being stored)
370: *
371: * @param value boolean
372: */
373: public void setUseCompression(boolean value) {
374: useCompression = value;
375: }
376:
377: /**
378: * Set this boolean indicating whether the file should be output
379: * in tar.gz format rather than .zip format.
380: *
381: * @param value boolean
382: */
383: public void setUseTarFormat(boolean value) {
384: useTarFormat = value;
385: }
386: }
|