blob: 757e97cb447eaad2adfcb1b7cd79122d1c80c71f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010 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.jst.j2ee.internal.archive.operations;
import static org.eclipse.jst.j2ee.datamodel.properties.IJ2EEComponentExportDataModelProperties.ARCHIVE_DESTINATION;
import static org.eclipse.jst.j2ee.datamodel.properties.IJ2EEComponentExportDataModelProperties.COMPONENT;
import static org.eclipse.jst.j2ee.datamodel.properties.IJ2EEComponentExportDataModelProperties.EXPORT_SOURCE_FILES;
import static org.eclipse.jst.j2ee.datamodel.properties.IJ2EEComponentExportDataModelProperties.OPTIMIZE_FOR_SPECIFIC_RUNTIME;
import static org.eclipse.jst.j2ee.datamodel.properties.IJ2EEComponentExportDataModelProperties.RUNTIME_SPECIFIC_PARTICIPANTS;
import static org.eclipse.jst.j2ee.datamodel.properties.IJ2EEComponentExportDataModelProperties.RUN_BUILD;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.ICommand;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceRuleFactory;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.runtime.jobs.MultiRule;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jst.j2ee.commonarchivecore.internal.CommonArchiveResourceHandler;
import org.eclipse.jst.j2ee.datamodel.properties.IJ2EEComponentExportDataModelProperties.IArchiveExportParticipantData;
import org.eclipse.jst.j2ee.internal.project.ProjectSupportResourceHandler;
import org.eclipse.jst.jee.archive.ArchiveSaveFailureException;
import org.eclipse.jst.jee.archive.internal.ArchiveUtil;
import org.eclipse.osgi.util.NLS;
import org.eclipse.wst.common.componentcore.internal.flat.IFlattenParticipant;
import org.eclipse.wst.common.componentcore.resources.IVirtualComponent;
import org.eclipse.wst.common.componentcore.resources.IVirtualReference;
import org.eclipse.wst.common.frameworks.datamodel.AbstractDataModelOperation;
import org.eclipse.wst.common.frameworks.datamodel.IDataModel;
import org.eclipse.wst.common.frameworks.datamodel.IDataModelOperation;
public class ComponentExportOperation extends AbstractDataModelOperation {
protected IProgressMonitor progressMonitor;
private IVirtualComponent component;
private IPath destinationPath;
private boolean exportSource = false;
public static String[] DOT_FILE_NAMES = new String[] {
".project", //$NON-NLS-1$
".classpath", //$NON-NLS-1$
".cvsignore", //$NON-NLS-1$
};
public static String[] DOT_SOURCE_FILES = new String[] {
".java", //$NON-NLS-1$
".sqlj", //$NON-NLS-1$
};
public ComponentExportOperation() {
super();
}
public ComponentExportOperation(IDataModel model) {
super(model);
}
protected final int REFRESH_WORK = 100;
protected final int JAVA_BUILDER_WORK = 100;
protected final int EXPORT_WORK = 1000;
protected final int CLOSE_WORK = 10;
protected final int SINGLE_PARTICIPANT_WORK = 200;
protected int computeTotalWork() {
int totalWork = REFRESH_WORK;
if (model.getBooleanProperty(RUN_BUILD)) {
totalWork += JAVA_BUILDER_WORK;
}
totalWork += EXPORT_WORK + CLOSE_WORK;
final IDataModel dm = getDataModel();
if (dm.getProperty(OPTIMIZE_FOR_SPECIFIC_RUNTIME) == Boolean.TRUE) {
final List<IArchiveExportParticipantData> extensions
= (List<IArchiveExportParticipantData>) dm.getProperty(RUNTIME_SPECIFIC_PARTICIPANTS);
totalWork += extensions.size() * SINGLE_PARTICIPANT_WORK;
}
return totalWork;
}
@Override
public IStatus execute(IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
setComponent((IVirtualComponent) model.getProperty(COMPONENT));
setDestinationPath(new Path(model.getStringProperty(ARCHIVE_DESTINATION)));
setExportSource(model.getBooleanProperty(EXPORT_SOURCE_FILES));
try {
monitor.beginTask(ProjectSupportResourceHandler.getString(ProjectSupportResourceHandler.Exporting_archive, new Object [] { getDestinationPath().lastSegment() }), computeTotalWork());
setProgressMonitor(monitor);
try {
component.getProject().refreshLocal(IResource.DEPTH_INFINITE, new SubProgressMonitor(monitor, REFRESH_WORK));
if (model.getBooleanProperty(RUN_BUILD)) {
IVirtualReference[] refs = component.getReferences();
int work = (JAVA_BUILDER_WORK) / (refs.length + 1);
runNecessaryBuilders(component, new SubProgressMonitor(monitor, work));
for (int i = 0; i < refs.length; i++) {
IVirtualComponent refComp = refs[i].getReferencedComponent();
runNecessaryBuilders(refComp, new SubProgressMonitor(monitor, work));
}
}
export();
} catch (Exception e) {
throw new ExecutionException(EJBArchiveOpsResourceHandler.Error_exporting__UI_ + getDestinationPath(), e);
}
final IDataModel dm = getDataModel();
if (dm.getProperty(OPTIMIZE_FOR_SPECIFIC_RUNTIME) == Boolean.TRUE) {
for (IArchiveExportParticipantData extData : (List<IArchiveExportParticipantData>) dm.getProperty( RUNTIME_SPECIFIC_PARTICIPANTS)) {
final IDataModelOperation op = extData.getParticipant().createOperation( extData.getDataModel() );
op.execute(null, null);
monitor.worked(SINGLE_PARTICIPANT_WORK);
}
}
}
finally {
monitor.done();
}
return OK_STATUS;
}
public void export() throws ArchiveSaveFailureException {
IProgressMonitor subMonitor = new SubProgressMonitor(progressMonitor, EXPORT_WORK);
final int SAVE_TICKS = 198;
final int CLEANUP_TICKS = 2;
final int TOTAL_TICKS = SAVE_TICKS + CLEANUP_TICKS;
try {
File writeFile = getDestinationPath().toFile();
if (writeFile.exists()) {
writeFile.delete();
}
java.io.File aFile = getDestinationPath().toFile();
ArchiveUtil.checkWriteable(aFile);
boolean fileExisted = aFile.exists();
FlatComponentArchiver archiver = null;
try {
java.io.File destinationFile = fileExisted
? ArchiveUtil.createTempFile(getDestinationPath().toOSString(), aFile.getCanonicalFile().getParentFile())
: aFile;
java.io.OutputStream out = createOutputStream(destinationFile);
archiver = createFlatComponentArchiver(out);
subMonitor.beginTask(NLS.bind(CommonArchiveResourceHandler.ArchiveFactoryImpl_Saving_archive_to_0_, getDestinationPath().toOSString()), TOTAL_TICKS);
archiver.saveArchive();
subMonitor.worked(SAVE_TICKS);
archiver.close();
if (fileExisted) {
ArchiveUtil.cleanupAfterTempSave(getDestinationPath().toOSString(), aFile, destinationFile);
}
subMonitor.worked(CLEANUP_TICKS);
} catch (java.io.IOException e) {
throw new ArchiveSaveFailureException(e);
} catch (ArchiveSaveFailureException failure) {
try {
archiver.close();
} catch (IOException weTried) {
// Ignore
}
if (!fileExisted)
aFile.delete();
throw failure;
}
} finally {
subMonitor.done();
}
}
protected java.io.OutputStream createOutputStream(java.io.File destinationFile) throws IOException, FileNotFoundException {
if (destinationFile.exists() && destinationFile.isDirectory()) {
throw new IOException(NLS.bind(CommonArchiveResourceHandler.ArchiveFactoryImpl_The_specified_file_0_exists_and_, destinationFile.getAbsolutePath()));
}
java.io.File parent = destinationFile.getParentFile();
if (parent != null)
parent.mkdirs();
java.io.OutputStream out = new java.io.FileOutputStream(destinationFile);
return out;
}
protected FlatComponentArchiver createFlatComponentArchiver(OutputStream out) {
return new FlatComponentArchiver(getComponent(), out, getParticipants());
}
protected void setProgressMonitor(IProgressMonitor newProgressMonitor) {
progressMonitor = newProgressMonitor;
}
protected IProgressMonitor getProgressMonitor() {
return progressMonitor;
}
private void setComponent(IVirtualComponent newComponent) {
component = newComponent;
}
protected IVirtualComponent getComponent() {
if (component == null)
component = (IVirtualComponent) model.getProperty(COMPONENT);
return component;
}
protected IPath getDestinationPath() {
return destinationPath;
}
protected void setDestinationPath(IPath newDestinationPath) {
destinationPath = newDestinationPath;
}
protected boolean isExportSource() {
return exportSource;
}
protected void setExportSource(boolean newExportSource) {
exportSource = newExportSource;
}
protected void runNecessaryBuilders(IVirtualComponent component, IProgressMonitor monitor) throws CoreException {
try {
monitor.beginTask(null, JAVA_BUILDER_WORK);
if (!component.isBinary()) {
IProject project = component.getProject();
IProjectDescription description = project.getDescription();
ICommand javaBuilder = getJavaCommand(description);
if (javaBuilder != null) {
project.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, JavaCore.BUILDER_ID, javaBuilder.getArguments(), new SubProgressMonitor(monitor, JAVA_BUILDER_WORK));
}
}
} finally {
monitor.done();
}
}
/**
* Find the specific Java command amongst the build spec of a given description
*/
protected ICommand getJavaCommand(IProjectDescription description) throws CoreException {
if (description == null) {
return null;
}
ICommand[] commands = description.getBuildSpec();
for (int i = 0; i < commands.length; ++i) {
if (commands[i].getBuilderName().equals(JavaCore.BUILDER_ID)) {
return commands[i];
}
}
return null;
}
@Override
public ISchedulingRule getSchedulingRule() {
Set projs = gatherDependentProjects(getComponent(), new HashSet());
ISchedulingRule combinedRule = null;
IResourceRuleFactory ruleFactory = ResourcesPlugin.getWorkspace().getRuleFactory();
for (Iterator iter = projs.iterator(); iter.hasNext();) {
IProject proj = (IProject) iter.next();
ISchedulingRule rule = ruleFactory.createRule(proj);
combinedRule = MultiRule.combine(rule, combinedRule);
}
combinedRule = MultiRule.combine(ruleFactory.buildRule(), combinedRule);
return combinedRule;
}
/**
* Subclasses can provide a list of participants who may
* be involved in forming the export model
*
* A deployable with no participant should still properly
* consume consumed references and traverse the model appropriately
*
* @return
*/
protected List<IFlattenParticipant> getParticipants() {
return Collections.EMPTY_LIST;
}
protected String[] getFilteredExtensions() {
ArrayList<String> excludeList = new ArrayList<String>();
excludeList.addAll(Arrays.asList(DOT_FILE_NAMES));
if (!isExportSource()) {
excludeList.addAll(Arrays.asList(DOT_SOURCE_FILES));
}
return excludeList.toArray(new String[excludeList.size()]);
}
private Set gatherDependentProjects(IVirtualComponent comp, Set projs) {
if (!projs.contains(comp.getProject())) {
projs.add(comp.getProject());
IVirtualReference[] refs = comp.getReferences();
for (int i = 0; i < refs.length; i++) {
IVirtualReference refComp = refs[i];
projs.addAll(gatherDependentProjects(refComp.getReferencedComponent(), projs));
}
}
return projs;
}
}