/******************************************************************************* * Copyright (c) 2009 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * Zend Technologies *******************************************************************************/ package org.eclipse.php.internal.ui.phar.wizard; import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.HashSet; import java.util.Set; import org.eclipse.core.resources.*; import org.eclipse.core.runtime.*; import org.eclipse.dltk.core.*; import org.eclipse.jface.operation.ModalContext; import org.eclipse.php.internal.core.phar.PharPackage; import org.eclipse.php.internal.core.project.PHPNature; import org.eclipse.php.internal.ui.PHPUiPlugin; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.actions.WorkspaceModifyOperation; public class PharFileExportOperation extends WorkspaceModifyOperation implements IPharExportRunnable { private static class MessageMultiStatus extends MultiStatus { MessageMultiStatus(String pluginId, int code, String message, Throwable exception) { super(pluginId, code, message, exception); } /* * allows to change the message */ @Override protected void setMessage(String message) { super.setMessage(message); } } private IPharBuilder fJarBuilder; private PharPackage fJarPackage; private PharPackage[] fJarPackages; private Shell fParentShell; private MessageMultiStatus fStatus; private Set<IResource> resourceSet = new HashSet<>(); /** * Creates an instance of this class. * * @param jarPackage * the JAR package specification * @param parent * the parent for the dialog, or <code>null</code> if no dialog * should be presented */ public PharFileExportOperation(PharPackage jarPackage, Shell parent) { this(new PharPackage[] { jarPackage }, parent); } /** * Creates an instance of this class. * * @param jarPackages * an array with JAR package data objects * @param parent * the parent for the dialog, or <code>null</code> if no dialog * should be presented */ public PharFileExportOperation(PharPackage[] jarPackages, Shell parent) { this(parent); fJarPackages = jarPackages; } private PharFileExportOperation(Shell parent) { fParentShell = parent; fStatus = new MessageMultiStatus(PHPUiPlugin.getPluginId(), IStatus.OK, "", null); //$NON-NLS-1$ // standardModelElementContentProvider= new // StandardModelElementContentProvider(); } private void addToStatus(CoreException ex) { IStatus status = ex.getStatus(); String message = ex.getLocalizedMessage(); if (message == null || message.length() < 1) { message = ""; //$NON-NLS-1$ status = new Status(status.getSeverity(), status.getPlugin(), status.getCode(), message, ex); } fStatus.add(status); } /** * Adds a new info to the list with the passed information. Normally the * export operation continues after a warning. * * @param message * the message * @param error * the throwable that caused the warning, or <code>null</code> */ protected void addInfo(String message, Throwable error) { fStatus.add(new Status(IStatus.INFO, PHPUiPlugin.getPluginId(), 10001, message, error)); } /** * Adds a new warning to the list with the passed information. Normally the * export operation continues after a warning. * * @param message * the message * @param error * the throwable that caused the warning, or <code>null</code> */ private void addWarning(String message, Throwable error) { fStatus.add(new Status(IStatus.WARNING, PHPUiPlugin.getPluginId(), 10001, message, error)); } /** * Adds a new error to the list with the passed information. Normally an * error terminates the export operation. * * @param message * the message * @param error * the throwable that caused the error, or <code>null</code> */ private void addError(String message, Throwable error) { fStatus.add(new Status(IStatus.ERROR, PHPUiPlugin.getPluginId(), 10001, message, error)); } /** * Answers the number of file resources specified by the JAR package. * * @return int */ private int countSelectedElements() { Set enclosingJavaProjects = new HashSet(10); int count = 0; int n = fJarPackage.getElements().length; for (int i = 0; i < n; i++) { Object element = fJarPackage.getElements()[i]; IScriptProject javaProject = getEnclosingJavaProject(element); if (javaProject != null) enclosingJavaProjects.add(javaProject); IResource resource = null; if (element instanceof IModelElement) { IModelElement je = (IModelElement) element; resource = je.getResource(); if (resource == null) { continue; } } else if (element instanceof IResource) { resource = (IResource) element; } if (resource != null) { if (resource.getType() == IResource.FILE) count++; else count += getTotalChildCount((IContainer) resource); } } return count; } private int getTotalChildCount(IContainer container) { IResource[] members; try { members = container.members(); } catch (CoreException ex) { return 0; } int count = 0; for (int i = 0; i < members.length; i++) { if (members[i].getType() == IResource.FILE) count++; else count += getTotalChildCount((IContainer) members[i]); } return count; } /** * Exports the passed resource to the JAR file * * @param element * the resource or JavaElement to export * @param progressMonitor * the progress monitor * @throws InterruptedException * thrown on cancel */ private void exportElement(Object element, IProgressMonitor progressMonitor) throws InterruptedException { int leadSegmentsToRemove = 1; IProjectFragment pkgRoot = null; boolean isInJavaProject = false; IResource resource = null; // ITypeRoot typeRootElement= null; IScriptProject jProject = null; if (element instanceof IModelElement) { isInJavaProject = true; IModelElement je = (IModelElement) element; jProject = je.getScriptProject(); try { pkgRoot = jProject.getProjectFragment(je.getCorrespondingResource()); } catch (ModelException e) { e.printStackTrace(); } resource = je.getResource(); } else if (element instanceof IResource) { resource = (IResource) element; } else { return; } if (!resource.isAccessible()) { addWarning("", null); //$NON-NLS-1$ return; } if (!isInJavaProject) { // check if it's a Java resource try { isInJavaProject = resource.getProject().hasNature(PHPNature.ID); } catch (CoreException ex) { addWarning("", ex); //$NON-NLS-1$ return; } if (isInJavaProject) { // IModelElement je= DLTKCore.create(resource); // if (je instanceof ITypeRoot && je.exists()) { // exportElement(je, progressMonitor); // return; // } jProject = DLTKCore.create(resource.getProject()); try { IProjectFragment pkgFragment = jProject .findProjectFragment(resource.getFullPath().removeLastSegments(1)); if (pkgFragment != null) pkgRoot = pkgFragment; else pkgRoot = findPackageFragmentRoot(jProject, resource.getFullPath().removeLastSegments(1)); } catch (ModelException ex) { addWarning("", ex); //$NON-NLS-1$ return; } } } if (pkgRoot != null && jProject != null) { leadSegmentsToRemove = pkgRoot.getPath().segmentCount(); boolean isOnBuildPath; isOnBuildPath = jProject.isOnBuildpath(resource); if (!isOnBuildPath || (!pkgRoot.getElementName().equals(IProjectFragment.DEFAULT_PACKAGE_ROOT))) leadSegmentsToRemove--; } IPath destinationPath = resource.getFullPath().removeFirstSegments(leadSegmentsToRemove); if (resource.getType() == IResource.FILE) { exportResource(progressMonitor, resource, destinationPath); progressMonitor.worked(1); ModalContext.checkCanceled(progressMonitor); } else { if (fJarPackage.areDirectoryEntriesIncluded()) { exportResource(progressMonitor, resource, destinationPath.append(File.separator)); progressMonitor.worked(1); ModalContext.checkCanceled(progressMonitor); } exportContainer(progressMonitor, (IContainer) resource); } } private void exportContainer(IProgressMonitor progressMonitor, IContainer container) throws InterruptedException { IResource[] children = null; try { children = container.members(); } catch (CoreException exception) { // this should never happen because an #isAccessible check is done // before #members is invoked addWarning("", exception); //$NON-NLS-1$ } if (children != null) { for (int i = 0; i < children.length; i++) { IResource child = children[i]; exportElement(child, progressMonitor); } } } private IProjectFragment findPackageFragmentRoot(IScriptProject jProject, IPath path) throws ModelException { if (jProject == null || path == null || path.segmentCount() <= 0) return null; IProjectFragment pkgRoot = jProject.findProjectFragment(path); if (pkgRoot != null) return pkgRoot; else return findPackageFragmentRoot(jProject, path.removeLastSegments(1)); } private void exportResource(IProgressMonitor progressMonitor, IResource resource, IPath destinationPath) { try { if (resource instanceof IFile) { progressMonitor.subTask(""); //$NON-NLS-1$ fJarBuilder.writeFile((IFile) resource, destinationPath); } else { progressMonitor.subTask(""); //$NON-NLS-1$ fJarBuilder.writeFile((IFolder) resource, destinationPath); } } catch (CoreException ex) { handleCoreExceptionOnExport(ex); } } /** * Exports the resources as specified by the JAR package. * * @param progressMonitor * the progress monitor * @throws InterruptedException * thrown when cancelled */ private void exportSelectedElements(IProgressMonitor progressMonitor) throws InterruptedException { int n = fJarPackage.getElements().length; for (int i = 0; i < n; i++) { Object element = fJarPackage.getElements()[i]; exportElement(element, progressMonitor); } } private IScriptProject getEnclosingJavaProject(Object element) { if (element instanceof IModelElement) { return ((IModelElement) element).getScriptProject(); } else if (element instanceof IResource) { IProject project = ((IResource) element).getProject(); try { if (project.hasNature(PHPNature.ID)) return DLTKCore.create(project); } catch (CoreException ex) { addWarning("", ex); //$NON-NLS-1$ } } return null; } /** * Handles core exceptions that are thrown by * {@link IJarBuilder#writeFile(IFile, IPath)}. * * @param ex * the core exception * @since 3.5 */ private void handleCoreExceptionOnExport(CoreException ex) { Throwable realEx = ex.getStatus().getException(); if (realEx instanceof IOException && realEx.getMessage() != null && realEx.getMessage().startsWith("duplicate entry:")) // hardcoded //$NON-NLS-1$ // message // string // from // java.util.zip.ZipOutputStream.putNextEntry(ZipEntry) addWarning(ex.getMessage(), realEx); else addToStatus(ex); } /** * Returns the status of this operation. The result is a status object * containing individual status objects. * * @return the status of this operation */ @Override public IStatus getStatus() { String message = null; switch (fStatus.getSeverity()) { case IStatus.OK: message = PharPackagerMessages.PharFileExportOperation_10; break; case IStatus.INFO: message = PharPackagerMessages.PharFileExportOperation_11; break; case IStatus.WARNING: message = PharPackagerMessages.PharFileExportOperation_12; break; case IStatus.ERROR: if (fJarPackages.length > 1) message = PharPackagerMessages.PharFileExportOperation_13; else message = PharPackagerMessages.PharFileExportOperation_13; break; default: // defensive code in case new severity is defined message = ""; //$NON-NLS-1$ break; } fStatus.setMessage(message); return fStatus; } /** * Exports the resources as specified by the JAR package. * * @param progressMonitor * the progress monitor that displays the progress * @throws InvocationTargetException * thrown when an ecxeption occurred * @throws InterruptedException * thrown when cancelled * @see #getStatus() */ @Override protected void execute(IProgressMonitor progressMonitor) throws InvocationTargetException, InterruptedException { int count = fJarPackages.length; progressMonitor.beginTask("", count); //$NON-NLS-1$ try { for (int i = 0; i < count; i++) { SubProgressMonitor subProgressMonitor = new SubProgressMonitor(progressMonitor, 1, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK); fJarPackage = fJarPackages[i]; if (fJarPackage != null) singleRun(subProgressMonitor); } } finally { progressMonitor.done(); } } private void singleRun(IProgressMonitor progressMonitor) throws InvocationTargetException, InterruptedException { try { if (!preconditionsOK()) throw new InvocationTargetException(null, ""); //$NON-NLS-1$ int totalWork = countSelectedElements(); progressMonitor.beginTask("", totalWork); //$NON-NLS-1$ fJarBuilder = PharExportHelper.createPlainPharBuilder(fJarPackage); // fJarBuilder = new PlainPharBuilder(); fJarBuilder.open(fJarPackage, fParentShell, fStatus); fJarBuilder.writeStub(fJarBuilder.getStubProvider().create(fJarPackage), progressMonitor); exportSelectedElements(progressMonitor); fJarBuilder.writeSignature(progressMonitor); // if (getStatus().getSeverity() != IStatus.ERROR) { // progressMonitor.subTask(""); // saveFiles(); // } } catch (CoreException ex) { addToStatus(ex); } finally { try { if (fJarBuilder != null) fJarBuilder.close(); } catch (CoreException ex) { addToStatus(ex); } progressMonitor.done(); } } private boolean preconditionsOK() { // if (!fJarPackage.areGeneratedFilesExported() && // !fJarPackage.areJavaFilesExported()) { // addError(JarPackagerMessages.JarFileExportOperation_noExportTypeChosen, // null); // return false; // } if (fJarPackage.getElements() == null || fJarPackage.getElements().length == 0) { addError(PharPackagerMessages.JarFileExportOperation_noResourcesSelected, null); return false; } if (fJarPackage.getAbsolutePharLocation() == null) { addError(PharPackagerMessages.JarFileExportOperation_invalidJarLocation, null); return false; } File targetFile = fJarPackage.getAbsolutePharLocation().toFile(); if (targetFile.exists() && !targetFile.canWrite()) { addError(PharPackagerMessages.JarFileExportOperation_jarFileExistsAndNotWritable, null); return false; } if (!fJarPackage.isStubAccessible()) { addError(PharPackagerMessages.JarFileExportOperation_manifestDoesNotExist, null); return false; } return true; } // private void saveFiles() { // // Save the manifest // if (fJarPackage.isStubGenerated()) { // try { // saveManifest(); // } catch (CoreException ex) { // addError( // JarPackagerMessages.JarFileExportOperation_errorSavingManifest, // ex); // } catch (IOException ex) { // addError( // JarPackagerMessages.JarFileExportOperation_errorSavingManifest, // ex); // } // } // } // private void saveManifest() throws CoreException, IOException { // ByteArrayOutputStream stubOutput = new ByteArrayOutputStream(); // IStub stub = fJarBuilder.getStubProvider().create(fJarPackage); // stub.write(stubOutput); // } }