1 /*******************************************************************************
2 * Copyright (c) 2000, 2003 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpeclipse.obfuscator.export;
14 import java.io.IOException;
15 import java.util.ArrayList;
16 import java.util.HashMap;
17 import java.util.Iterator;
18 import java.util.List;
20 import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
21 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
22 import net.sourceforge.phpeclipse.obfuscator.ObfuscatorIgnores;
23 import net.sourceforge.phpeclipse.obfuscator.ObfuscatorPass1Exporter;
24 import net.sourceforge.phpeclipse.obfuscator.ObfuscatorPass2Exporter;
26 import org.eclipse.core.resources.IContainer;
27 import org.eclipse.core.resources.IFile;
28 import org.eclipse.core.resources.IProject;
29 import org.eclipse.core.resources.IResource;
30 import org.eclipse.core.runtime.CoreException;
31 import org.eclipse.core.runtime.IPath;
32 import org.eclipse.core.runtime.IProgressMonitor;
33 import org.eclipse.core.runtime.IStatus;
34 import org.eclipse.core.runtime.MultiStatus;
35 import org.eclipse.core.runtime.Path;
36 import org.eclipse.core.runtime.Status;
37 import org.eclipse.jface.operation.IRunnableWithProgress;
38 import org.eclipse.jface.operation.ModalContext;
39 import org.eclipse.jface.preference.IPreferenceStore;
40 import org.eclipse.ui.PlatformUI;
41 import org.eclipse.ui.dialogs.IOverwriteQuery;
44 * Operation for exporting the contents of a resource to the local file system.
47 class ObfuscatorExportOperation implements IRunnableWithProgress {
50 private IProgressMonitor fMonitor;
52 private ObfuscatorPass1Exporter fExporter1 = null;
54 private ObfuscatorPass2Exporter fExporter2 = null;
56 private HashMap fCurrentIdentifierMap = null;
58 private HashMap fProjectMap = null;
60 private String fCurrentProjectName = "";
62 private List fResourcesToExport;
64 private IOverwriteQuery fOverwriteCallback;
66 private IResource fResource;
68 private List errorTable = new ArrayList(1);
70 // The constants for the overwrite 3 state
71 private static final int OVERWRITE_NOT_SET = 0;
73 private static final int OVERWRITE_NONE = 1;
75 private static final int OVERWRITE_ALL = 2;
77 private int overwriteState = OVERWRITE_NOT_SET;
79 // private boolean createLeadupStructure = true;
80 private boolean createContainerDirectories = true;
83 * Create an instance of this class. Use this constructor if you wish to
84 * export specific resources without a common parent resource
86 // public ObfuscatorExportOperation(List resources, String destinationPath,
87 // IOverwriteQuery overwriteImplementor) {
90 // exporter1 = new ObfuscatorPass1Exporter(new Scanner(false, false),
92 // exporter2 = new ObfuscatorPass2Exporter(new Scanner(true, true),
94 // identifierMap = null;
96 // // Eliminate redundancies in list of resources being exported
97 // Iterator elementsEnum = resources.iterator();
98 // while (elementsEnum.hasNext()) {
99 // IResource currentResource = (IResource) elementsEnum.next();
100 // if (isDescendent(resources, currentResource))
101 // elementsEnum.remove(); //Remove currentResource
104 // resourcesToExport = resources;
105 // path = new Path(destinationPath);
106 // overwriteCallback = overwriteImplementor;
109 * Create an instance of this class. Use this constructor if you wish to
110 * recursively export a single resource
112 public ObfuscatorExportOperation(IResource res, String destinationPath,
113 IOverwriteQuery overwriteImplementor) {
117 fPath = new Path(destinationPath);
118 fOverwriteCallback = overwriteImplementor;
122 * Create an instance of this class. Use this constructor if you wish to
123 * export specific resources with a common parent resource (affects
124 * container directory creation)
126 public ObfuscatorExportOperation(IResource res, List resources,
127 String destinationPath, IOverwriteQuery overwriteImplementor) {
128 this(res, destinationPath, overwriteImplementor);
129 fResourcesToExport = resources;
133 * Add a new entry to the error table with the passed information
135 protected void addError(String message, Throwable e) {
136 errorTable.add(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0,
141 * Answer the total number of file resources that exist at or below self in
142 * the resources hierarchy.
146 * org.eclipse.core.resources.IResource
148 protected int countChildrenOf(IResource resource) throws CoreException {
149 if (resource.getType() == IResource.FILE)
153 if (resource.isAccessible()) {
154 IResource[] children = ((IContainer) resource).members();
155 for (int i = 0; i < children.length; i++)
156 count += countChildrenOf(children[i]);
163 * Answer a boolean indicating the number of file resources that were
164 * specified for export
168 protected int countSelectedResources() throws CoreException {
170 Iterator resources = fResourcesToExport.iterator();
172 while (resources.hasNext())
173 result += countChildrenOf((IResource) resources.next());
179 * Create the directories required for exporting the passed resource, based
180 * upon its container hierarchy
183 * org.eclipse.core.resources.IResource
185 protected void createLeadupDirectoriesFor(IResource resource) {
186 IPath resourcePath = resource.getFullPath().removeLastSegments(1);
188 for (int i = 0; i < resourcePath.segmentCount(); i++) {
189 fPath = fPath.append(resourcePath.segment(i));
190 fExporter2.createFolder(fPath);
195 * Recursively export the previously-specified resource
197 protected void exportAllResources1() throws InterruptedException {
198 if (fResource.getType() == IResource.FILE) {
199 exportFile1((IFile) fResource, fPath);
202 setExporters(fResource);
203 exportChildren1(((IContainer) fResource).members(), fPath);
204 } catch (CoreException e) {
205 // not safe to show a dialog
206 // should never happen because the file system export wizard
208 // single resource chosen for export is both existent and
216 * Recursively export the previously-specified resource
218 protected void exportAllResources2() throws InterruptedException {
219 if (fResource.getType() == IResource.FILE) {
220 exportFile2((IFile) fResource, fPath);
223 setExporters(fResource);
224 exportChildren2(((IContainer) fResource).members(), fPath);
225 } catch (CoreException e) {
226 // not safe to show a dialog
227 // should never happen because the file system export wizard
229 // single resource chosen for export is both existent and
237 * Export all of the resources contained in the passed collection
240 * java.util.Enumeration
244 protected void exportChildren1(IResource[] children, IPath currentPath)
245 throws InterruptedException {
246 for (int i = 0; i < children.length; i++) {
247 IResource child = children[i];
248 if (!child.isAccessible())
251 if (child.getType() == IResource.FILE)
252 exportFile1((IFile) child, currentPath);
254 IPath destination = currentPath.append(child.getName());
255 fExporter1.createFolder(destination);
257 exportChildren1(((IContainer) child).members(), destination);
258 } catch (CoreException e) {
259 // not safe to show a dialog
260 // should never happen because:
261 // i. this method is called recursively iterating over the
262 // result of #members,
263 // which only answers existing children
264 // ii. there is an #isAccessible check done before #members
266 errorTable.add(e.getStatus());
273 * Export all of the resources contained in the passed collection
276 * java.util.Enumeration
280 protected void exportChildren2(IResource[] children, IPath currentPath)
281 throws InterruptedException {
282 for (int i = 0; i < children.length; i++) {
283 IResource child = children[i];
284 if (!child.isAccessible())
287 if (child.getType() == IResource.FILE)
288 exportFile2((IFile) child, currentPath);
290 IPath destination = currentPath.append(child.getName());
291 fExporter2.createFolder(destination);
293 exportChildren2(((IContainer) child).members(), destination);
294 } catch (CoreException e) {
295 // not safe to show a dialog
296 // should never happen because:
297 // i. this method is called recursively iterating over the
298 // result of #members,
299 // which only answers existing children
300 // ii. there is an #isAccessible check done before #members
302 errorTable.add(e.getStatus());
308 protected void exportFile1(IFile file, IPath location)
309 throws InterruptedException {
310 IPath fullPath = location.append(file.getName());
311 fMonitor.subTask(file.getFullPath().toString());
312 String properPathString = fullPath.toOSString();
313 File targetFile = new File(properPathString);
315 // if (targetFile.exists()) {
316 // if (!targetFile.canWrite()) {
317 // errorTable.add(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0,
318 // ObfuscatorExportMessages.format("ObfuscatorTransfer.cannotOverwrite",
320 // new Object[] { targetFile.getAbsolutePath()}), null));
321 // monitor.worked(1);
325 // if (overwriteState == OVERWRITE_NONE)
328 // if (overwriteState != OVERWRITE_ALL) {
329 // String overwriteAnswer =
330 // overwriteCallback.queryOverwrite(properPathString);
332 // if (overwriteAnswer.equals(IOverwriteQuery.CANCEL))
333 // throw new InterruptedException();
335 // if (overwriteAnswer.equals(IOverwriteQuery.NO)) {
336 // monitor.worked(1);
340 // if (overwriteAnswer.equals(IOverwriteQuery.NO_ALL)) {
341 // monitor.worked(1);
342 // overwriteState = OVERWRITE_NONE;
346 // if (overwriteAnswer.equals(IOverwriteQuery.ALL))
347 // overwriteState = OVERWRITE_ALL;
353 fExporter1.write(file, fullPath);
354 } catch (IOException e) {
355 errorTable.add(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0,
356 ObfuscatorExportMessages.format(
357 "ObfuscatorTransfer.errorExporting", //$NON-NLS-1$
358 new Object[] { fullPath, e.getMessage() }), e));
359 } catch (CoreException e) {
360 errorTable.add(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0,
361 ObfuscatorExportMessages.format(
362 "ObfuscatorTransfer.errorExporting", //$NON-NLS-1$
363 new Object[] { fullPath, e.getMessage() }), e));
367 ModalContext.checkCanceled(fMonitor);
371 * Export the passed file to the specified location
374 * org.eclipse.core.resources.IFile
376 * org.eclipse.core.runtime.IPath
378 protected void exportFile2(IFile file, IPath location)
379 throws InterruptedException {
380 IPath fullPath = location.append(file.getName());
381 fMonitor.subTask(file.getFullPath().toString());
382 String properPathString = fullPath.toOSString();
383 File targetFile = new File(properPathString);
385 if (targetFile.exists()) {
386 if (!targetFile.canWrite()) {
387 errorTable.add(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID,
388 0, ObfuscatorExportMessages.format(
389 "ObfuscatorTransfer.cannotOverwrite", //$NON-NLS-1$
390 new Object[] { targetFile.getAbsolutePath() }),
396 if (overwriteState == OVERWRITE_NONE)
399 if (overwriteState != OVERWRITE_ALL) {
400 String overwriteAnswer = fOverwriteCallback
401 .queryOverwrite(properPathString);
403 if (overwriteAnswer.equals(IOverwriteQuery.CANCEL))
404 throw new InterruptedException();
406 if (overwriteAnswer.equals(IOverwriteQuery.NO)) {
411 if (overwriteAnswer.equals(IOverwriteQuery.NO_ALL)) {
413 overwriteState = OVERWRITE_NONE;
417 if (overwriteAnswer.equals(IOverwriteQuery.ALL))
418 overwriteState = OVERWRITE_ALL;
424 fExporter2.write(file, fullPath);
425 } catch (IOException e) {
426 errorTable.add(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0,
427 ObfuscatorExportMessages.format(
428 "ObfuscatorTransfer.errorExporting", //$NON-NLS-1$
429 new Object[] { fullPath, e.getMessage() }), e));
430 } catch (CoreException e) {
431 errorTable.add(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0,
432 ObfuscatorExportMessages.format(
433 "ObfuscatorTransfer.errorExporting", //$NON-NLS-1$
434 new Object[] { fullPath, e.getMessage() }), e));
438 ModalContext.checkCanceled(fMonitor);
441 protected void exportSpecifiedResources1() throws InterruptedException {
442 Iterator resources = fResourcesToExport.iterator();
443 IPath initPath = (IPath) fPath.clone();
445 while (resources.hasNext()) {
446 IResource currentResource = (IResource) resources.next();
447 if (!currentResource.isAccessible())
449 setExporters(currentResource);
452 if (fResource == null) {
453 // No root resource specified and creation of containment
455 // is required. Create containers from depth 2 onwards (ie.-
457 // child inclusive) for each resource being exported.
458 // if (createLeadupStructure)
459 // createLeadupDirectoriesFor(currentResource);
462 // Root resource specified. Must create containment directories
463 // from this point onwards for each resource being exported
464 IPath containersToCreate = currentResource.getFullPath()
465 .removeFirstSegments(
466 fResource.getFullPath().segmentCount())
467 .removeLastSegments(1);
469 for (int i = 0; i < containersToCreate.segmentCount(); i++) {
470 fPath = fPath.append(containersToCreate.segment(i));
471 fExporter1.createFolder(fPath);
475 if (currentResource.getType() == IResource.FILE)
476 exportFile1((IFile) currentResource, fPath);
478 if (createContainerDirectories) {
479 fPath = fPath.append(currentResource.getName());
480 fExporter1.createFolder(fPath);
484 exportChildren1(((IContainer) currentResource).members(),
486 } catch (CoreException e) {
487 // should never happen because #isAccessible is called
488 // before #members is invoked,
489 // which implicitly does an existence check
490 errorTable.add(e.getStatus());
497 * Export the resources contained in the previously-defined
498 * resourcesToExport collection
500 protected void exportSpecifiedResources2() throws InterruptedException {
501 Iterator resources = fResourcesToExport.iterator();
502 IPath initPath = (IPath) fPath.clone();
504 while (resources.hasNext()) {
505 IResource currentResource = (IResource) resources.next();
506 if (!currentResource.isAccessible())
508 setExporters(currentResource);
512 if (fResource == null) {
513 // No root resource specified and creation of containment
515 // is required. Create containers from depth 2 onwards (ie.-
517 // child inclusive) for each resource being exported.
518 // if (createLeadupStructure)
519 // createLeadupDirectoriesFor(currentResource);
522 // Root resource specified. Must create containment directories
523 // from this point onwards for each resource being exported
524 IPath containersToCreate = currentResource.getFullPath()
525 .removeFirstSegments(
526 fResource.getFullPath().segmentCount())
527 .removeLastSegments(1);
529 for (int i = 0; i < containersToCreate.segmentCount(); i++) {
530 fPath = fPath.append(containersToCreate.segment(i));
531 fExporter2.createFolder(fPath);
535 if (currentResource.getType() == IResource.FILE)
536 exportFile2((IFile) currentResource, fPath);
538 if (createContainerDirectories) {
539 fPath = fPath.append(currentResource.getName());
540 fExporter2.createFolder(fPath);
544 exportChildren2(((IContainer) currentResource).members(),
546 } catch (CoreException e) {
547 // should never happen because #isAccessible is called
548 // before #members is invoked,
549 // which implicitly does an existence check
550 errorTable.add(e.getStatus());
557 * Returns the status of the export operation. If there were any errors, the
558 * result is a status object containing individual status objects for each
559 * error. If there were no errors, the result is a status object with error
560 * code <code>OK</code>.
564 public IStatus getStatus() {
565 IStatus[] errors = new IStatus[errorTable.size()];
566 errorTable.toArray(errors);
567 return new MultiStatus(
568 PlatformUI.PLUGIN_ID,
571 ObfuscatorExportMessages
572 .getString("ObfuscatorExportOperation.problemsExporting"), //$NON-NLS-1$
577 * Answer a boolean indicating whether the passed child is a descendent of
578 * one or more members of the passed resources collection
584 * org.eclipse.core.resources.IResource
586 protected boolean isDescendent(List resources, IResource child) {
587 if (child.getType() == IResource.PROJECT)
590 IResource parent = child.getParent();
591 if (resources.contains(parent))
594 return isDescendent(resources, parent);
597 private void setExporters(IResource resource) {
598 if (fCurrentIdentifierMap == null) {
599 if (fProjectMap == null) {
600 fProjectMap = new HashMap();
602 createExporters(resource);
604 IProject project = resource.getProject();
605 if (!fCurrentProjectName.equals(project.getName())) {
606 HashMap temp = (HashMap) fProjectMap.get(project.getName());
608 fCurrentProjectName = project.getName();
609 fCurrentIdentifierMap = temp;
610 fExporter1 = new ObfuscatorPass1Exporter(new Scanner(false,
611 false), fCurrentIdentifierMap);
612 fExporter2 = new ObfuscatorPass2Exporter(new Scanner(true,
613 true), fCurrentIdentifierMap);
616 createExporters(resource);
621 private void createExporters(IResource resource) {
622 IProject project = resource.getProject();
623 IPreferenceStore store = PHPeclipsePlugin.getDefault()
624 .getPreferenceStore();
625 ObfuscatorIgnores ignore = new ObfuscatorIgnores(project);
626 fCurrentIdentifierMap = ignore.getIdentifierMap();
627 fCurrentProjectName = project.getName();
628 fProjectMap.put(fCurrentProjectName, fCurrentIdentifierMap);
629 fExporter1 = new ObfuscatorPass1Exporter(new Scanner(false, false),
630 fCurrentIdentifierMap);
631 fExporter2 = new ObfuscatorPass2Exporter(new Scanner(true, true),
632 fCurrentIdentifierMap);
636 * Export the resources that were previously specified for export (or if a
637 * single resource was specified then export it recursively)
639 public void run(IProgressMonitor monitor) throws InterruptedException {
640 this.fMonitor = monitor;
641 final IPath tempPath = (IPath) fPath.clone();
642 if (fResource != null) {
643 setExporters(fResource);
644 // if (createLeadupStructure)
645 // createLeadupDirectoriesFor(resource);
647 if (createContainerDirectories
648 && fResource.getType() != IResource.FILE) {
649 // ensure it's a container
650 fPath = fPath.append(fResource.getName());
651 fExporter2.createFolder(fPath);
656 // reset variables for this run:
657 fCurrentIdentifierMap = null;
659 fCurrentProjectName = "";
661 // count number of files
662 int totalWork = IProgressMonitor.UNKNOWN;
664 if (fResourcesToExport == null) {
665 totalWork = countChildrenOf(fResource);
667 totalWork = countSelectedResources();
669 } catch (CoreException e) {
671 errorTable.add(e.getStatus());
675 ObfuscatorExportMessages
676 .getString("ObfuscatorTransfer.exportingTitle1"), totalWork); //$NON-NLS-1$
677 if (fResourcesToExport == null) {
678 exportAllResources1();
680 exportSpecifiedResources1();
684 // if (resourcesToExport == null)
685 // totalWork = countChildrenOf(resource);
687 // totalWork = countSelectedResources();
688 // } catch (CoreException e) {
689 // // Should not happen
690 // errorTable.add(e.getStatus());
697 ObfuscatorExportMessages
698 .getString("ObfuscatorTransfer.exportingTitle2"), totalWork); //$NON-NLS-1$
699 if (fResourcesToExport == null) {
700 exportAllResources2();
702 exportSpecifiedResources2();
710 * Set this boolean indicating whether a directory should be created for
711 * Folder resources that are explicitly passed for export
716 // public void setCreateContainerDirectories(boolean value) {
717 // createContainerDirectories = value;
720 * Set this boolean indicating whether each exported resource's complete
721 * path should include containment hierarchies as dictated by its parents
726 // public void setCreateLeadupStructure(boolean value) {
727 // createLeadupStructure = value;
730 * Set this boolean indicating whether exported resources should
731 * automatically overwrite existing files when a conflict occurs. If not
737 public void setOverwriteFiles(boolean value) {
739 overwriteState = OVERWRITE_ALL;