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;
45 * Operation for exporting the contents of a resource to the local file system.
48 class ObfuscatorExportOperation implements IRunnableWithProgress {
50 private IProgressMonitor fMonitor;
51 private ObfuscatorPass1Exporter fExporter1 = null;
52 private ObfuscatorPass2Exporter fExporter2 = null;
53 private HashMap fCurrentIdentifierMap = null;
54 private HashMap fProjectMap = null;
55 private String fCurrentProjectName = "";
57 private List fResourcesToExport;
58 private IOverwriteQuery fOverwriteCallback;
59 private IResource fResource;
60 private List errorTable = new ArrayList(1);
62 //The constants for the overwrite 3 state
63 private static final int OVERWRITE_NOT_SET = 0;
64 private static final int OVERWRITE_NONE = 1;
65 private static final int OVERWRITE_ALL = 2;
66 private int overwriteState = OVERWRITE_NOT_SET;
68 // private boolean createLeadupStructure = true;
69 private boolean createContainerDirectories = true;
71 * Create an instance of this class. Use this constructor if you wish to
72 * export specific resources without a common parent resource
74 // public ObfuscatorExportOperation(List resources, String destinationPath, IOverwriteQuery overwriteImplementor) {
77 // exporter1 = new ObfuscatorPass1Exporter(new Scanner(false, false), identifierMap);
78 // exporter2 = new ObfuscatorPass2Exporter(new Scanner(true, true), identifierMap);
79 // identifierMap = null;
81 // // Eliminate redundancies in list of resources being exported
82 // Iterator elementsEnum = resources.iterator();
83 // while (elementsEnum.hasNext()) {
84 // IResource currentResource = (IResource) elementsEnum.next();
85 // if (isDescendent(resources, currentResource))
86 // elementsEnum.remove(); //Remove currentResource
89 // resourcesToExport = resources;
90 // path = new Path(destinationPath);
91 // overwriteCallback = overwriteImplementor;
94 * Create an instance of this class. Use this constructor if you wish to
95 * recursively export a single resource
97 public ObfuscatorExportOperation(IResource res, String destinationPath, IOverwriteQuery overwriteImplementor) {
101 fPath = new Path(destinationPath);
102 fOverwriteCallback = overwriteImplementor;
105 * Create an instance of this class. Use this constructor if you wish to
106 * export specific resources with a common parent resource (affects container
107 * directory creation)
109 public ObfuscatorExportOperation(IResource res, List resources, String destinationPath, IOverwriteQuery overwriteImplementor) {
110 this(res, destinationPath, overwriteImplementor);
111 fResourcesToExport = resources;
114 * Add a new entry to the error table with the passed information
116 protected void addError(String message, Throwable e) {
117 errorTable.add(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, message, e));
120 * Answer the total number of file resources that exist at or below self in the
121 * resources hierarchy.
124 * @param resource org.eclipse.core.resources.IResource
126 protected int countChildrenOf(IResource resource) throws CoreException {
127 if (resource.getType() == IResource.FILE)
131 if (resource.isAccessible()) {
132 IResource[] children = ((IContainer) resource).members();
133 for (int i = 0; i < children.length; i++)
134 count += countChildrenOf(children[i]);
140 * Answer a boolean indicating the number of file resources that were
141 * specified for export
145 protected int countSelectedResources() throws CoreException {
147 Iterator resources = fResourcesToExport.iterator();
149 while (resources.hasNext())
150 result += countChildrenOf((IResource) resources.next());
155 * Create the directories required for exporting the passed resource,
156 * based upon its container hierarchy
158 * @param resource org.eclipse.core.resources.IResource
160 protected void createLeadupDirectoriesFor(IResource resource) {
161 IPath resourcePath = resource.getFullPath().removeLastSegments(1);
163 for (int i = 0; i < resourcePath.segmentCount(); i++) {
164 fPath = fPath.append(resourcePath.segment(i));
165 fExporter2.createFolder(fPath);
169 * Recursively export the previously-specified resource
171 protected void exportAllResources1() throws InterruptedException {
172 if (fResource.getType() == IResource.FILE) {
173 exportFile1((IFile) fResource, fPath);
176 setExporters(fResource);
177 exportChildren1(((IContainer) fResource).members(), fPath);
178 } catch (CoreException e) {
179 // not safe to show a dialog
180 // should never happen because the file system export wizard ensures that the
181 // single resource chosen for export is both existent and accessible
187 * Recursively export the previously-specified resource
189 protected void exportAllResources2() throws InterruptedException {
190 if (fResource.getType() == IResource.FILE) {
191 exportFile2((IFile) fResource, fPath);
194 setExporters(fResource);
195 exportChildren2(((IContainer) fResource).members(), fPath);
196 } catch (CoreException e) {
197 // not safe to show a dialog
198 // should never happen because the file system export wizard ensures that the
199 // single resource chosen for export is both existent and accessible
205 * Export all of the resources contained in the passed collection
207 * @param children java.util.Enumeration
208 * @param currentPath IPath
210 protected void exportChildren1(IResource[] children, IPath currentPath) throws InterruptedException {
211 for (int i = 0; i < children.length; i++) {
212 IResource child = children[i];
213 if (!child.isAccessible())
216 if (child.getType() == IResource.FILE)
217 exportFile1((IFile) child, currentPath);
219 IPath destination = currentPath.append(child.getName());
220 fExporter1.createFolder(destination);
222 exportChildren1(((IContainer) child).members(), destination);
223 } catch (CoreException e) {
224 // not safe to show a dialog
225 // should never happen because:
226 // i. this method is called recursively iterating over the result of #members,
227 // which only answers existing children
228 // ii. there is an #isAccessible check done before #members is invoked
229 errorTable.add(e.getStatus());
236 * Export all of the resources contained in the passed collection
238 * @param children java.util.Enumeration
239 * @param currentPath IPath
241 protected void exportChildren2(IResource[] children, IPath currentPath) throws InterruptedException {
242 for (int i = 0; i < children.length; i++) {
243 IResource child = children[i];
244 if (!child.isAccessible())
247 if (child.getType() == IResource.FILE)
248 exportFile2((IFile) child, currentPath);
250 IPath destination = currentPath.append(child.getName());
251 fExporter2.createFolder(destination);
253 exportChildren2(((IContainer) child).members(), destination);
254 } catch (CoreException e) {
255 // not safe to show a dialog
256 // should never happen because:
257 // i. this method is called recursively iterating over the result of #members,
258 // which only answers existing children
259 // ii. there is an #isAccessible check done before #members is invoked
260 errorTable.add(e.getStatus());
266 protected void exportFile1(IFile file, IPath location) throws InterruptedException {
267 IPath fullPath = location.append(file.getName());
268 fMonitor.subTask(file.getFullPath().toString());
269 String properPathString = fullPath.toOSString();
270 File targetFile = new File(properPathString);
272 // if (targetFile.exists()) {
273 // if (!targetFile.canWrite()) {
274 // errorTable.add(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, ObfuscatorExportMessages.format("ObfuscatorTransfer.cannotOverwrite", //$NON-NLS-1$
275 // new Object[] { targetFile.getAbsolutePath()}), null));
276 // monitor.worked(1);
280 // if (overwriteState == OVERWRITE_NONE)
283 // if (overwriteState != OVERWRITE_ALL) {
284 // String overwriteAnswer = overwriteCallback.queryOverwrite(properPathString);
286 // if (overwriteAnswer.equals(IOverwriteQuery.CANCEL))
287 // throw new InterruptedException();
289 // if (overwriteAnswer.equals(IOverwriteQuery.NO)) {
290 // monitor.worked(1);
294 // if (overwriteAnswer.equals(IOverwriteQuery.NO_ALL)) {
295 // monitor.worked(1);
296 // overwriteState = OVERWRITE_NONE;
300 // if (overwriteAnswer.equals(IOverwriteQuery.ALL))
301 // overwriteState = OVERWRITE_ALL;
307 fExporter1.write(file, fullPath);
308 } catch (IOException e) {
309 errorTable.add(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, ObfuscatorExportMessages.format("ObfuscatorTransfer.errorExporting", //$NON-NLS-1$
310 new Object[] { fullPath, e.getMessage()}), e));
311 } catch (CoreException e) {
312 errorTable.add(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, ObfuscatorExportMessages.format("ObfuscatorTransfer.errorExporting", //$NON-NLS-1$
313 new Object[] { fullPath, e.getMessage()}), e));
317 ModalContext.checkCanceled(fMonitor);
320 * Export the passed file to the specified location
322 * @param file org.eclipse.core.resources.IFile
323 * @param location org.eclipse.core.runtime.IPath
325 protected void exportFile2(IFile file, IPath location) throws InterruptedException {
326 IPath fullPath = location.append(file.getName());
327 fMonitor.subTask(file.getFullPath().toString());
328 String properPathString = fullPath.toOSString();
329 File targetFile = new File(properPathString);
331 if (targetFile.exists()) {
332 if (!targetFile.canWrite()) {
333 errorTable.add(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, ObfuscatorExportMessages.format("ObfuscatorTransfer.cannotOverwrite", //$NON-NLS-1$
334 new Object[] { targetFile.getAbsolutePath()}), null));
339 if (overwriteState == OVERWRITE_NONE)
342 if (overwriteState != OVERWRITE_ALL) {
343 String overwriteAnswer = fOverwriteCallback.queryOverwrite(properPathString);
345 if (overwriteAnswer.equals(IOverwriteQuery.CANCEL))
346 throw new InterruptedException();
348 if (overwriteAnswer.equals(IOverwriteQuery.NO)) {
353 if (overwriteAnswer.equals(IOverwriteQuery.NO_ALL)) {
355 overwriteState = OVERWRITE_NONE;
359 if (overwriteAnswer.equals(IOverwriteQuery.ALL))
360 overwriteState = OVERWRITE_ALL;
366 fExporter2.write(file, fullPath);
367 } catch (IOException e) {
368 errorTable.add(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, ObfuscatorExportMessages.format("ObfuscatorTransfer.errorExporting", //$NON-NLS-1$
369 new Object[] { fullPath, e.getMessage()}), e));
370 } catch (CoreException e) {
371 errorTable.add(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, ObfuscatorExportMessages.format("ObfuscatorTransfer.errorExporting", //$NON-NLS-1$
372 new Object[] { fullPath, e.getMessage()}), e));
376 ModalContext.checkCanceled(fMonitor);
379 protected void exportSpecifiedResources1() throws InterruptedException {
380 Iterator resources = fResourcesToExport.iterator();
381 IPath initPath = (IPath) fPath.clone();
383 while (resources.hasNext()) {
384 IResource currentResource = (IResource) resources.next();
385 if (!currentResource.isAccessible())
387 setExporters(currentResource);
390 if (fResource == null) {
391 // No root resource specified and creation of containment directories
392 // is required. Create containers from depth 2 onwards (ie.- project's
393 // child inclusive) for each resource being exported.
394 // if (createLeadupStructure)
395 // createLeadupDirectoriesFor(currentResource);
398 // Root resource specified. Must create containment directories
399 // from this point onwards for each resource being exported
400 IPath containersToCreate =
401 currentResource.getFullPath().removeFirstSegments(fResource.getFullPath().segmentCount()).removeLastSegments(1);
403 for (int i = 0; i < containersToCreate.segmentCount(); i++) {
404 fPath = fPath.append(containersToCreate.segment(i));
405 fExporter1.createFolder(fPath);
409 if (currentResource.getType() == IResource.FILE)
410 exportFile1((IFile) currentResource, fPath);
412 if (createContainerDirectories) {
413 fPath = fPath.append(currentResource.getName());
414 fExporter1.createFolder(fPath);
418 exportChildren1(((IContainer) currentResource).members(), fPath);
419 } catch (CoreException e) {
420 // should never happen because #isAccessible is called before #members is invoked,
421 // which implicitly does an existence check
422 errorTable.add(e.getStatus());
428 * Export the resources contained in the previously-defined
429 * resourcesToExport collection
431 protected void exportSpecifiedResources2() throws InterruptedException {
432 Iterator resources = fResourcesToExport.iterator();
433 IPath initPath = (IPath) fPath.clone();
435 while (resources.hasNext()) {
436 IResource currentResource = (IResource) resources.next();
437 if (!currentResource.isAccessible())
439 setExporters(currentResource);
443 if (fResource == null) {
444 // No root resource specified and creation of containment directories
445 // is required. Create containers from depth 2 onwards (ie.- project's
446 // child inclusive) for each resource being exported.
447 // if (createLeadupStructure)
448 // createLeadupDirectoriesFor(currentResource);
451 // Root resource specified. Must create containment directories
452 // from this point onwards for each resource being exported
453 IPath containersToCreate =
454 currentResource.getFullPath().removeFirstSegments(fResource.getFullPath().segmentCount()).removeLastSegments(1);
456 for (int i = 0; i < containersToCreate.segmentCount(); i++) {
457 fPath = fPath.append(containersToCreate.segment(i));
458 fExporter2.createFolder(fPath);
462 if (currentResource.getType() == IResource.FILE)
463 exportFile2((IFile) currentResource, fPath);
465 if (createContainerDirectories) {
466 fPath = fPath.append(currentResource.getName());
467 fExporter2.createFolder(fPath);
471 exportChildren2(((IContainer) currentResource).members(), fPath);
472 } catch (CoreException e) {
473 // should never happen because #isAccessible is called before #members is invoked,
474 // which implicitly does an existence check
475 errorTable.add(e.getStatus());
481 * Returns the status of the export operation.
482 * If there were any errors, the result is a status object containing
483 * individual status objects for each error.
484 * If there were no errors, the result is a status object with error code <code>OK</code>.
488 public IStatus getStatus() {
489 IStatus[] errors = new IStatus[errorTable.size()];
490 errorTable.toArray(errors);
491 return new MultiStatus(PlatformUI.PLUGIN_ID, IStatus.OK, errors, ObfuscatorExportMessages.getString("ObfuscatorExportOperation.problemsExporting"), //$NON-NLS-1$
495 * Answer a boolean indicating whether the passed child is a descendent
496 * of one or more members of the passed resources collection
499 * @param resources java.util.List
500 * @param child org.eclipse.core.resources.IResource
502 protected boolean isDescendent(List resources, IResource child) {
503 if (child.getType() == IResource.PROJECT)
506 IResource parent = child.getParent();
507 if (resources.contains(parent))
510 return isDescendent(resources, parent);
513 private void setExporters(IResource resource) {
514 if (fCurrentIdentifierMap == null) {
515 if (fProjectMap == null) {
516 fProjectMap = new HashMap();
518 createExporters(resource);
520 IProject project = resource.getProject();
521 if (!fCurrentProjectName.equals(project.getName())) {
522 HashMap temp = (HashMap) fProjectMap.get(project.getName());
524 fCurrentProjectName = project.getName();
525 fCurrentIdentifierMap = temp;
526 fExporter1 = new ObfuscatorPass1Exporter(new Scanner(false, false), fCurrentIdentifierMap);
527 fExporter2 = new ObfuscatorPass2Exporter(new Scanner(true, true), fCurrentIdentifierMap);
530 createExporters(resource);
535 private void createExporters(IResource resource) {
536 IProject project = resource.getProject();
537 IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
538 ObfuscatorIgnores ignore = new ObfuscatorIgnores(project);
539 fCurrentIdentifierMap = ignore.getIdentifierMap();
540 fCurrentProjectName = project.getName();
541 fProjectMap.put(fCurrentProjectName, fCurrentIdentifierMap);
542 fExporter1 = new ObfuscatorPass1Exporter(new Scanner(false, false), fCurrentIdentifierMap);
543 fExporter2 = new ObfuscatorPass2Exporter(new Scanner(true, true), fCurrentIdentifierMap);
546 * Export the resources that were previously specified for export
547 * (or if a single resource was specified then export it recursively)
549 public void run(IProgressMonitor monitor) throws InterruptedException {
550 this.fMonitor = monitor;
551 final IPath tempPath = (IPath) fPath.clone();
552 if (fResource != null) {
553 setExporters(fResource);
554 // if (createLeadupStructure)
555 // createLeadupDirectoriesFor(resource);
557 if (createContainerDirectories && fResource.getType() != IResource.FILE) {
558 // ensure it's a container
559 fPath = fPath.append(fResource.getName());
560 fExporter2.createFolder(fPath);
565 // reset variables for this run:
566 fCurrentIdentifierMap = null;
568 fCurrentProjectName = "";
570 // count number of files
571 int totalWork = IProgressMonitor.UNKNOWN;
573 if (fResourcesToExport == null) {
574 totalWork = countChildrenOf(fResource);
576 totalWork = countSelectedResources();
578 } catch (CoreException e) {
580 errorTable.add(e.getStatus());
582 monitor.beginTask(ObfuscatorExportMessages.getString("ObfuscatorTransfer.exportingTitle1"), totalWork); //$NON-NLS-1$
583 if (fResourcesToExport == null) {
584 exportAllResources1();
586 exportSpecifiedResources1();
590 // if (resourcesToExport == null)
591 // totalWork = countChildrenOf(resource);
593 // totalWork = countSelectedResources();
594 // } catch (CoreException e) {
595 // // Should not happen
596 // errorTable.add(e.getStatus());
601 monitor.beginTask(ObfuscatorExportMessages.getString("ObfuscatorTransfer.exportingTitle2"), totalWork); //$NON-NLS-1$
602 if (fResourcesToExport == null) {
603 exportAllResources2();
605 exportSpecifiedResources2();
612 * Set this boolean indicating whether a directory should be created for
613 * Folder resources that are explicitly passed for export
615 * @param value boolean
617 // public void setCreateContainerDirectories(boolean value) {
618 // createContainerDirectories = value;
621 * Set this boolean indicating whether each exported resource's complete path should
622 * include containment hierarchies as dictated by its parents
624 * @param value boolean
626 // public void setCreateLeadupStructure(boolean value) {
627 // createLeadupStructure = value;
630 * Set this boolean indicating whether exported resources should automatically
631 * overwrite existing files when a conflict occurs. If not
634 * @param value boolean
636 public void setOverwriteFiles(boolean value) {
638 overwriteState = OVERWRITE_ALL;