/*******************************************************************************
* Copyright © 2000, 2013 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
*
*******************************************************************************/
package org.eclipse.edt.ide.ui.internal.eglarpackager;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import java.util.zip.ZipException;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jdt.ui.jarpackager.IJarBuilder;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.eclipse.edt.ide.core.model.IEGLElement;
import org.eclipse.edt.ide.core.model.EGLModelException;
import org.eclipse.edt.ide.core.model.IEGLPathEntry;
import org.eclipse.edt.ide.core.model.IEGLProject;
import org.eclipse.edt.ide.ui.EDTUIPlugin;
import org.eclipse.edt.ide.ui.internal.property.pages.BasicElementLabels;
import org.eclipse.edt.ide.ui.internal.property.pages.Messages;
public class EglarFileExportOperation extends WorkspaceModifyOperation implements IEglarExportRunnable {
public static final int INTERNAL_ERROR= 10001;
public static final String EGLAR_FILE_EXTENSION = ".eglar";
private static class MessageMultiStatus extends MultiStatus {
MessageMultiStatus(String pluginId, int code, String message, Throwable exception) {
super(pluginId, code, message, exception);
}
protected void setMessage(String message) {
super.setMessage(message);
}
}
private IEglarBinaryProjectBuilder fEglarBuilder;
private EglarPackageData fEglarPackage;
private EglarPackageData[] fEglarPackages;
private Shell fParentShell;
private MessageMultiStatus fStatus;
private boolean fFilesSaved;
protected int totalWork;
private int irFileCounts = 0;
protected int[] irFileCountsPerElements = new int[0];
protected boolean singleEGLARExport = true;
private int work = 0;
/**
* Creates an instance of this class.
*
* @param eglarPackage the eglar package specification
* @param parent the parent for the dialog,
* or <code>null</code> if no dialog should be presented
*/
public EglarFileExportOperation(EglarPackageData eglarPackage, Shell parent) {
this(new EglarPackageData[] {eglarPackage}, parent);
}
/**
* Creates an instance of this class.
*
* @param eglarPackages an array with eglar package data objects
* @param parent the parent for the dialog,
* or <code>null</code> if no dialog should be presented
*/
public EglarFileExportOperation(EglarPackageData[] eglarPackages, Shell parent) {
this(parent);
fEglarPackages= eglarPackages;
}
private EglarFileExportOperation(Shell parent) {
fParentShell= parent;
fStatus= new MessageMultiStatus(EDTUIPlugin.getPluginId(), IStatus.OK, "", null); //$NON-NLS-1$
}
/**
*
* @return
*/
public IEglarBinaryProjectBuilder getfEglarBuilder() {
return fEglarBuilder;
}
/**
*
* @param fEglarBuilder
*/
public void setfEglarBuilder(IEglarBinaryProjectBuilder fEglarBuilder) {
this.fEglarBuilder = fEglarBuilder;
}
/**
*
* @return
*/
public EglarPackageData getfEglarPackage() {
return fEglarPackage;
}
/**
*
* @param fEglarPackage
*/
public void setfEglarPackage(EglarPackageData fEglarPackage) {
this.fEglarPackage = fEglarPackage;
}
/**
*
* @return
*/
public EglarPackageData[] getfEglarPackages() {
return fEglarPackages;
}
/**
*
* @param fEglarPackages
*/
public void setfEglarPackages(EglarPackageData[] fEglarPackages) {
this.fEglarPackages = fEglarPackages;
}
/**
*
* @return
*/
public Shell getfParentShell() {
return fParentShell;
}
/**
*
* @param fParentShell
*/
public void setfParentShell(Shell fParentShell) {
this.fParentShell = fParentShell;
}
/**
*
* @return
*/
public MessageMultiStatus getfStatus() {
return fStatus;
}
/**
*
* @param fStatus
*/
public void setfStatus(MessageMultiStatus fStatus) {
this.fStatus = fStatus;
}
protected void addToStatus(CoreException ex) {
IStatus status= ex.getStatus();
String message= ex.getLocalizedMessage();
if (message == null || message.length() < 1) {
message= EglarPackagerMessages.EglarFileExportOperation_coreErrorDuringExport;
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, EDTUIPlugin.getPluginId(), INTERNAL_ERROR, 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>
*/
protected void addWarning(String message, Throwable error) {
fStatus.add(new Status(IStatus.WARNING, EDTUIPlugin.getPluginId(), INTERNAL_ERROR, 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>
*/
protected void addError(String message, Throwable error) {
fStatus.add(new Status(IStatus.ERROR, EDTUIPlugin.getPluginId(), INTERNAL_ERROR, message, error));
}
/**
* Answers the number of file resources specified by the Eglar package.
*
* @return int
*/
protected int countSelectedElements() {
// Set enclosingEGLProjects= new HashSet(10);
int count= 0;
int n= fEglarPackage.getElements().length;
irFileCountsPerElements = new int[n];
for (int i= 0; i < n; i++) {
Object element= fEglarPackage.getElements()[i];
// IEGLProject eglProject= (IEGLProject)element;//getEnclosingEGLProject(element);
// if (eglProject != null)
// enclosingEGLProjects.add(eglProject);
IResource resource= null;
if (element instanceof IEGLElement) {
IEGLElement ee= (IEGLElement)element;
resource= ee.getResource();
} else if (element instanceof IResource) {
resource= (IResource) element;
}
if (resource != null) {
if (resource.getType() == IResource.FILE) {
count++;
if(isIRFile(resource) || isRequiredResourceFile(resource)) {
irFileCounts++;
irFileCountsPerElements[i]++;
}
}
else
count+= getTotalChildCount((IContainer) resource, i);
}
}
return count;
}
private int getTotalChildCount(IContainer container, int elementIndex) {
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++;
if(isIRFile(members[i]) || isRequiredResourceFile(members[i])) {
irFileCounts ++;
irFileCountsPerElements[elementIndex]++;
}
}
else
count += getTotalChildCount((IContainer)members[i], elementIndex);
}
return count;
}
/**
* Exports the resources as specified by the Eglar package.
* @param progressMonitor the progress monitor
* @throws InterruptedException thrown when cancelled
* @throws CoreException
*/
protected void exportSelectedElements(IProgressMonitor progressMonitor) throws InterruptedException, CoreException {
fEglarBuilder = fEglarPackage.getEglarBuilder();
fEglarBuilder.open(fEglarPackage, fParentShell, fStatus);
int n= fEglarPackage.getElements().length;
for (int i= 0; i < n; i++) {
Object element= fEglarPackage.getElements()[i];
try {
exportEGLProject2EGLAR((IEGLProject) element,progressMonitor);
if(fEglarPackage.areEGLSrcFilesExported()) {
exportEGLProject2SourceZip((IEGLProject) element, progressMonitor);
}
} catch (CoreException e) {
e.printStackTrace();
}
}
}
/**
*
* @param eglProject
* @param progressMonitor
* @throws CoreException
*/
protected void exportEGLProject2EGLAR(IEGLProject eglProject, final IProgressMonitor progressMonitor) throws CoreException {
IPath outputLocation = eglProject.getOutputLocation();
//For 69080: Export binary projects failed with console UI project
//If the project is from RBD801 or older, the ouptut directory is EGLBin, regardless of what is found in the .eglpath file
if(outputLocation != null && "bin".equalsIgnoreCase(outputLocation.lastSegment())) {
outputLocation = eglProject.getPath().append(NewEglarFileExportOperation.EGL_BIN_FOLDER);
}
IFolder outputFolder= createFolderHandle(outputLocation);
if(outputFolder != null) {
outputFolder.accept(new IResourceVisitor() {
public boolean visit(IResource resource) throws CoreException {
IPath path = resource.getFullPath();
if(isIRFile(resource) || isRequiredResourceFile(resource)) {
progressMonitor.worked(work++);
IPath classFilePath = path.removeFirstSegments(2);
IFile file = (IFile)resource;
progressMonitor.subTask(Messages.format(EglarPackagerMessages.EglarFileExportOperation_exporting, BasicElementLabels.getPathLabel(classFilePath, false)));
try {
fEglarBuilder.writeFile(file, classFilePath);
} catch (CoreException ex) {
handleCoreExceptionOnExport(ex);
}
return false;
}
return true;
}
});
}
}
/**
*
* @param eglProject
* @param progressMonitor
* @throws CoreException
*/
private void exportEGLProject2SourceZip(IEGLProject eglProject, final IProgressMonitor progressMonitor) throws CoreException {
IPath[] srcPaths = getEGLSourceFolder(eglProject);
for(IPath srcPath : srcPaths) {
IFolder srcFolder = createFolderHandle(srcPath);
if(srcFolder != null) {
srcFolder.accept(new IResourceVisitor() {
public boolean visit(IResource resource) throws CoreException {
IPath path = resource.getFullPath();
if(isEGLFile(resource)) {
progressMonitor.worked(work++);
IPath eglFilePath = path.removeFirstSegments(2);
IFile file = (IFile)resource;
progressMonitor.subTask(Messages.format(EglarPackagerMessages.EglarFileExportOperation_exporting, BasicElementLabels.getPathLabel(eglFilePath, false)));
try {
fEglarBuilder.writeEGLSourceFile(file, eglFilePath);
} catch (CoreException ex) {
handleCoreExceptionOnExport(ex);
}
return false;
}
return true;
}
});
}
}
}
/**
*
* @param ieglProject
* @return
*/
protected IPath[] getEGLSourceFolder(IEGLProject ieglProject) {
ArrayList<IPath> srcPathsArrayList = new ArrayList<IPath>();
try {
IEGLPathEntry[] entries = ieglProject.getRawEGLPath();
for(IEGLPathEntry entry : entries) {
if(entry.getEntryKind() == IEGLPathEntry.CPE_SOURCE) {
srcPathsArrayList.add(entry.getPath());
}
}
} catch (EGLModelException e) {
e.printStackTrace();
return new IPath[0];
}
IPath[] srcPathsArray = new IPath[srcPathsArrayList.size()];
srcPathsArrayList.toArray(srcPathsArray);
return srcPathsArray;
}
/**
* Answers whether the given resource is an egl file.
* The resource must be a file whose file name ends with ".egl",
* or an extension defined as egl source.
*
* @param file the file to test
* @return a <code>true<code> if the given resource is an egl file
*/
protected boolean isEGLFile(IResource file) {
return file != null
&& file.getType() == IResource.FILE
&& file.getFileExtension() != null
&& file.getFileExtension().toLowerCase().equals("egl");
}
/**
* Answers whether the given resource is a ir file.
* The resource must be a file whose file name ends with ".ir".
*
* @param file the file to test
* @return a <code>true<code> if the given resource is a ir file
*/
protected boolean isIRFile(IResource file) {
return file != null
&& file.getType() == IResource.FILE
&& file.getFileExtension() != null
&& file.getFileExtension().toLowerCase().equalsIgnoreCase("ir"); //$NON-NLS-1$
}
/**
*
* @param file
* @return
*/
protected boolean isRequiredResourceFile(IResource file) {
if (file != null && file.getType() == IResource.FILE
&& file.getFileExtension() != null) {
if(file.getFileExtension().toLowerCase().equalsIgnoreCase("wsdl")) {
return true;
}
}
return false;
}
/**
* Creates a folder resource handle for the folder with the given workspace path.
*
* @param folderPath the path of the folder to create a handle for
* @return the new folder resource handle
*/
private IFolder createFolderHandle(IPath folderPath) {
if (folderPath.isValidPath(folderPath.toString()) && folderPath.segmentCount() >= 2)
return ResourcesPlugin.getWorkspace().getRoot().getFolder(folderPath);
else
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 ZipException && realEx.getMessage() != null
&& realEx.getMessage().startsWith("duplicate entry:")) //$NON-NLS-1$ hardcoded 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
*/
public IStatus getStatus() {
String message= null;
switch (fStatus.getSeverity()) {
case IStatus.OK:
message= ""; //$NON-NLS-1$
break;
case IStatus.INFO:
message= EglarPackagerMessages.EglarFileExportOperation_exportFinishedWithInfo;
break;
case IStatus.WARNING:
message= EglarPackagerMessages.EglarFileExportOperation_exportFinishedWithWarnings;
break;
case IStatus.ERROR:
if (fEglarPackages.length > 1)
message= EglarPackagerMessages.EglarFileExportOperation_creationOfSomeEglarsFailed;
else
message= EglarPackagerMessages.EglarFileExportOperation_EglarCreationFailed;
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 Eglar package.
*
* @param progressMonitor the progress monitor that displays the progress
* @throws InvocationTargetException thrown when an ecxeption occurred
* @throws InterruptedException thrown when cancelled
* @see #getStatus()
*/
protected void execute(IProgressMonitor progressMonitor) throws InvocationTargetException, InterruptedException {
int count= fEglarPackages.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);
fEglarPackage= fEglarPackages[i];
if (fEglarPackage != null)
singleRun(subProgressMonitor);
}
} finally {
progressMonitor.done();
}
}
private void singleRun(IProgressMonitor progressMonitor) throws InvocationTargetException, InterruptedException {
try {
if (!preconditionsOK())
throw new InvocationTargetException(null, getExportOperationCreationFailedSeeDetailsMessage());
if (fEglarPackage.areGeneratedFilesExported()
&& ((!isAutoBuilding() && fEglarPackage.isBuildingIfNeeded())
|| (isAutoBuilding() && fFilesSaved))) {
int subMonitorTicks= totalWork/10;
totalWork += subMonitorTicks;
progressMonitor.beginTask("", totalWork); //$NON-NLS-1$
SubProgressMonitor subProgressMonitor= new SubProgressMonitor(progressMonitor, subMonitorTicks, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
buildProjects(subProgressMonitor);
} else
progressMonitor.beginTask("", totalWork); //$NON-NLS-1$
exportSelectedElements(progressMonitor);
} catch (CoreException ex) {
addToStatus(ex);
} finally {
try {
if (fEglarBuilder != null)
fEglarBuilder.close();
} catch (CoreException ex) {
addToStatus(ex);
}
progressMonitor.done();
}
}
protected String getExportOperationCreationFailedSeeDetailsMessage() {
return EglarPackagerMessages.EglarFileExportOperation_eglarCreationFailedSeeDetails;
}
protected boolean preconditionsOK() {
if (fEglarPackage.getElements() == null || fEglarPackage.getElements().length == 0) {
addError(EglarPackagerMessages.EglarFileExportOperation_noResourcesSelected, null);
return false;
}
if (fEglarPackage.getAbsoluteEglarLocation() == null) {
addError(EglarPackagerMessages.EglarFileExportOperation_invalidEglarLocation, null);
return false;
}
File targetFile= fEglarPackage.getAbsoluteEglarLocation().toFile();
if (targetFile.exists() && !targetFile.canWrite()) {
addError(EglarPackagerMessages.EglarFileExportOperation_EglarFileExistsAndNotWritable, null);
return false;
}
totalWork= countSelectedElements();
return true;
}
private boolean isAutoBuilding() {
//return ResourcesPlugin.getWorkspace().getDescription().isAutoBuilding();
return false;
}
private void buildProjects(IProgressMonitor progressMonitor) {
Set builtProjects= new HashSet(10);
Object[] elements= fEglarPackage.getElements();
for (int i= 0; i < elements.length; i++) {
IProject project= null;
Object element= elements[i];
if (element instanceof IResource)
project= ((IResource)element).getProject();
else if (element instanceof IEGLElement)
project= ((IEGLElement)element).getEGLProject().getProject();
if (project != null && !builtProjects.contains(project)) {
try {
project.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, progressMonitor);
} catch (CoreException ex) {
String message= Messages.format(EglarPackagerMessages.EglarFileExportOperation_errorDuringProjectBuild, BasicElementLabels.getResourceName(project));
addError(message, ex);
} finally {
// don't try to build same project a second time even if it failed
builtProjects.add(project);
}
}
}
}
/**
*
* @param eglProject
* @param folderPath
* @return
*/
protected boolean isBinaryFolder(IEGLProject eglProject, IPath folderPath) {
try {
IPath output = eglProject.getOutputLocation();
//For 69080: Export binary projects failed with console UI project
if(output != null && "bin".equalsIgnoreCase(output.lastSegment())) {
output = eglProject.getPath().append(NewEglarFileExportOperation.EGL_BIN_FOLDER);
}
return output.isPrefixOf(folderPath);
} catch (EGLModelException e) {
e.printStackTrace();
}
return false;
}
}