blob: f4a160d316c5a1494b98b593d9046bb855437c76 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 2005 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 java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspaceRoot;
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.SubProgressMonitor;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.URIConverter;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jem.util.emf.workbench.WorkbenchURIConverter;
import org.eclipse.jem.util.logger.proxy.Logger;
import org.eclipse.jem.workbench.utility.JemProjectUtilities;
import org.eclipse.jst.j2ee.commonarchivecore.internal.Archive;
import org.eclipse.jst.j2ee.commonarchivecore.internal.EARFile;
import org.eclipse.jst.j2ee.commonarchivecore.internal.File;
import org.eclipse.jst.j2ee.commonarchivecore.internal.exception.SaveFailureException;
import org.eclipse.jst.j2ee.commonarchivecore.internal.helpers.ArchiveConstants;
import org.eclipse.jst.j2ee.commonarchivecore.internal.helpers.ArchiveManifest;
import org.eclipse.jst.j2ee.commonarchivecore.internal.strategy.SaveStrategy;
import org.eclipse.jst.j2ee.commonarchivecore.internal.strategy.ZipStreamSaveStrategyImpl;
import org.eclipse.jst.j2ee.commonarchivecore.internal.util.ArchiveUtil;
import org.eclipse.jst.j2ee.datamodel.properties.IEARComponentImportDataModelProperties;
import org.eclipse.jst.j2ee.datamodel.properties.IJ2EEComponentImportDataModelProperties;
import org.eclipse.jst.j2ee.internal.earcreation.EAREditModel;
import org.eclipse.jst.j2ee.internal.earcreation.EARNatureRuntime;
import org.eclipse.jst.j2ee.internal.project.J2EEModuleNature;
import org.eclipse.jst.j2ee.internal.project.J2EENature;
import org.eclipse.wst.common.componentcore.internal.resources.VirtualComponent;
import org.eclipse.wst.common.frameworks.datamodel.IDataModel;
public class EARComponentSaveStrategyImpl extends J2EEComponentSaveStrategyImpl implements IJ2EEImportExportConstants {
protected IDataModel dataModel;
protected IProject project;
protected URIConverter earURIConverter;
protected IOverwriteHandler overwriteHandler;
protected IProgressMonitor monitor;
protected boolean includeProjectMetaFiles = false;
/**
* Used to store the actual project names used to create projects for the modules; needed for
* updating project class paths after all the projects have been saved
*/
protected Map createdProjectsMap;
public EARComponentSaveStrategyImpl(IDataModel dataModel) {
super((VirtualComponent) dataModel.getProperty(IEARComponentImportDataModelProperties.COMPONENT));
this.dataModel = dataModel;
project = (IProject) dataModel.getProperty(IEARComponentImportDataModelProperties.PROJECT);
setArchive((Archive) dataModel.getProperty(IEARComponentImportDataModelProperties.FILE));
overwriteHandler = (IOverwriteHandler) dataModel.getProperty(IEARComponentImportDataModelProperties.OVERWRITE_HANDLER);
if (null != overwriteHandler) {
overwriteHandler.setEarSaveStrategy(this);
}
buildProjectsMap();
}
/**
* Creates a Map mapping archive uris to projects for all archives in the ear that imported as
* projects.
*/
private void buildProjectsMap() {
createdProjectsMap = new HashMap();
List createdProjectsList = (List) dataModel.getProperty(IEARComponentImportDataModelProperties.ALL_PROJECT_MODELS_LIST);
IDataModel importDM = null;
Archive anArchive = null;
for (int i = 0; i < createdProjectsList.size(); i++) {
importDM = (IDataModel) createdProjectsList.get(i);
anArchive = (Archive) importDM.getProperty(IJ2EEComponentImportDataModelProperties.FILE);
createdProjectsMap.put(anArchive.getURI(), (IProject) importDM.getProperty(IJ2EEComponentImportDataModelProperties.PROJECT));
}
}
protected void addFileToClasspath(IProject p, IFile file, List cp) {
if (!file.exists())
return;
// Assume the file also contains the source
IPath path = file.getFullPath();
IClasspathEntry entry = JavaCore.newLibraryEntry(path, path, null, true);
if (!cp.contains(entry))
cp.add(entry);
}
protected void addProjectToClasspath(IProject dependent, IProject prereq, List cp) {
IClasspathEntry entry = JavaCore.newProjectEntry(prereq.getFullPath(), true);
if (!cp.contains(entry))
cp.add(entry);
}
protected SaveStrategy createNestedSaveStrategy(Archive anArchive) throws java.io.IOException {
try {
if (earURIConverter == null)
getEARURIConverter();
OutputStream out = earURIConverter.createOutputStream(URI.createURI(anArchive.getURI()));
return new ZipStreamSaveStrategyImpl(out);
} catch (Exception ex) {
throw new IOException(ex.getLocalizedMessage());
}
}
protected EARFile getEARFile() {
return (EARFile) getArchive();
}
public org.eclipse.emf.ecore.resource.URIConverter getEARURIConverter() {
EARNatureRuntime ear = EARNatureRuntime.getRuntime(project);
earURIConverter = ear.getResourceSet().getURIConverter();
return earURIConverter;
}
protected java.io.OutputStream getOutputStreamForResource(org.eclipse.emf.ecore.resource.Resource aResource) throws java.io.IOException {
return null;
}
public void save() throws SaveFailureException {
saveFiles();
saveManifest();
saveMofResources();
monitor.subTask(EARArchiveOpsResourceHandler.getString("Updating_project_classpath_UI_")); //$NON-NLS-1$ = "Updating project classpaths..."
updateProjectClasspaths();
}
public void save(ArchiveManifest aManifest) throws SaveFailureException {
try {
EARNatureRuntime ear = EARNatureRuntime.getRuntime(project);
if (ear == null)
throw new SaveFailureException(EARArchiveOpsResourceHandler.getString("ARCHIVE_OPERATION_ProjectNature")); //$NON-NLS-1$
URIConverter wuc = ear.getResourceSet().getURIConverter();
OutputStream out = wuc.createOutputStream(URI.createURI(ArchiveConstants.MANIFEST_URI));
aManifest.write(out);
out.close();
} catch (IOException ioe) {
throw new SaveFailureException(EARArchiveOpsResourceHandler.getString("ARCHIVE_OPERATION_SaveManifest")); //$NON-NLS-1$
}
}
public void save(Archive anArchive) throws SaveFailureException {
monitor.subTask(anArchive.getURI());
saveArchiveAsJARInEAR(anArchive);
}
protected void saveArchiveAsJARInEAR(Archive anArchive) throws SaveFailureException {
try {
anArchive.save(createNestedSaveStrategy(anArchive));
monitor.worked(1);
} catch (IOException e) {
throw new SaveFailureException(anArchive.getURI(), e);
}
}
public void save(File aFile, java.io.InputStream in) throws SaveFailureException {
monitor.subTask(aFile.getURI());
try {
if (earURIConverter == null)
getEARURIConverter();
IFile iFile = ((WorkbenchURIConverter) earURIConverter).getOutputFileWithMappingApplied(aFile.getURI());
mkdirs(iFile.getFullPath(), ResourcesPlugin.getWorkspace().getRoot());
if (iFile.exists())
iFile.setContents(in, true, true, null);
else
iFile.create(in, true, null);
// OutputStream out = earURIConverter.createOutputStream(URI.createURI(aFile.getURI()));
// ArchiveUtil.copy(in, out);
} catch (Exception iox) {
throw new SaveFailureException(aFile.getURI(), iox);
}
monitor.worked(1);
}
protected void mkdirs(IPath newPath, IWorkspaceRoot root) throws CoreException {
if (newPath.segmentCount() <= 2)
return;
IPath parentPath = newPath.removeLastSegments(1);
IFolder folder = root.getFolder(parentPath);
if (!folder.exists()) {
mkdirs(parentPath, root);
folder.create(true, true, null);
}
}
protected SubProgressMonitor subMonitor() {
return new SubProgressMonitor(monitor, 10);
}
public void saveMofResource(org.eclipse.emf.ecore.resource.Resource aResource) throws SaveFailureException {
setEncoding(aResource);
try {
if (earURIConverter == null)
getEARURIConverter();
OutputStream out = null;
out = earURIConverter.createOutputStream(aResource.getURI());
aResource.save(out, new HashMap());
out.close();
} catch (Exception e) {
String errorString = EARArchiveOpsResourceHandler.getString("ARCHIVE_OPERATION_SaveMofResources"); //$NON-NLS-1$
throw new SaveFailureException(errorString, e);
}
}
public void setMonitor(org.eclipse.core.runtime.IProgressMonitor newMonitor) {
monitor = newMonitor;
}
public void setProject(org.eclipse.core.resources.IProject newProject) {
project = newProject;
}
protected boolean shouldSave(File aFile) {
if (aFile.isArchive()) {
// TODO
// if (dataModel.handlesArchive((Archive) aFile)) {
// return false;
// }
return getFilter().shouldSave(aFile.getURI(), getArchive());
}
return super.shouldSave(aFile);
}
protected boolean isProjectMetaFile(String uri) {
return PROJECT_FILE_URI.equals(uri) || EAREditModel.MODULE_MAP_URI.equals(uri);
}
protected boolean shouldSave(String uri) {
if (isProjectMetaFile(uri))
return includeProjectMetaFiles;
if (shouldAlwaysExclude(uri)) {
return false;
}
if (overwriteHandler != null) {
if (overwriteHandler.isOverwriteNone())
return false;
return ((super.shouldSave(uri)) && (!overwriteHandler.isOverwriteResources()) && (!overwriteHandler.isOverwriteAll()) && (overwriteHandler.shouldOverwrite(uri)));
}
return true;
}
// TODO move up and use correct Strings
private boolean shouldAlwaysExclude(String uri) {
if (uri.equals(".runtime")) { //$NON-NLS-1$
return true;
}
return false;
}
/*
* Parse the manifest of the module file; for each cp entry 1) cananonicalize to a uri that
* looks like the entry in the ear 2) If the ear contains a file with that uri (the entry is
* valid) a) If the file is another was blown out to a project, add a cp entry for a referenced
* project b) otherwise, add a cp entry that points to the file in the ear project, and cp
* entries for all prereqs
*/
protected void updateProjectClasspath(Archive anArchive, IProject p) {
String message = EARArchiveOpsResourceHandler.getString("Updating_project_classpath_UI_") + p.getName(); //$NON-NLS-1$ = "Updating project classpaths..."
monitor.subTask(message);
List projectCpEntries = new ArrayList();
Set visited = new HashSet();
traverseClasspaths(p, anArchive, projectCpEntries, visited);
try {
if (!projectCpEntries.isEmpty())
JemProjectUtilities.appendJavaClassPath(p, projectCpEntries);
JemProjectUtilities.forceClasspathReload(p);
} catch (JavaModelException ex) {
org.eclipse.jem.util.logger.proxy.Logger.getLogger().logError(ex);
}
}
/*
* If you have a dependency to a JAR in the EAR project, and the JAR depends on another JAR in
* the EAR; you want to compile cleanly after import, so you need both those JARs on your build
* path
*/
protected void traverseClasspaths(IProject p, Archive anArchive, List projectCpEntries, Set visitedArchives) {
visitedArchives.add(anArchive);
String[] manifestCpEntries = anArchive.getManifest().getClassPathTokenized();
EARFile earFile = (EARFile) dataModel.getProperty(IJ2EEComponentImportDataModelProperties.FILE);
for (int i = 0; i < manifestCpEntries.length; i++) {
String uri = ArchiveUtil.deriveEARRelativeURI(manifestCpEntries[i], anArchive);
// ensure the entry is valid or skip to the next
if (uri == null)
continue;
File aFile = null;
try {
aFile = earFile.getFile(uri);
} catch (FileNotFoundException notThere) {
}
if (aFile == null || !aFile.isArchive() || visitedArchives.contains(aFile))
continue;
Archive depArchive = (Archive) aFile;
IProject prereq = (IProject) createdProjectsMap.get(uri);
if (prereq != null) {
addProjectToClasspath(p, prereq, projectCpEntries);
} else {
addFileToClasspath(p, project.getFile(uri), projectCpEntries);
traverseClasspaths(p, depArchive, projectCpEntries, visitedArchives);
}
}
}
protected void updateProjectClasspaths() {
// We're preserving the original classpath
if (includeProjectMetaFiles)
return;
List jarFiles = getEARFile().getArchiveFiles();
for (int i = 0; i < jarFiles.size(); i++) {
Archive anArchive = (Archive) jarFiles.get(i);
IProject p = (IProject) createdProjectsMap.get(anArchive.getURI());
if (p != null)
updateProjectClasspath(anArchive, p);
}
}
protected void ensureBinary(Archive anArchive, IProject p) {
// TODO
// if (!getImportConfiguration().isBinary(anArchive))
// return;
J2EEModuleNature nature = (J2EEModuleNature) J2EENature.getRegisteredRuntime(p);
// Right now WARs are not optimized
if (nature != null && !nature.canBeBinary())
return;
IJavaProject javaP = JemProjectUtilities.getJavaProject(p);
if (javaP == null)
return;
List newCp = new ArrayList();
try {
IClasspathEntry[] entries = javaP.getRawClasspath();
for (int i = 0; i < entries.length; i++) {
IClasspathEntry entry = entries[i];
if (entry.getEntryKind() != IClasspathEntry.CPE_SOURCE)
newCp.add(entry);
}
entries = (IClasspathEntry[]) newCp.toArray(new IClasspathEntry[newCp.size()]);
javaP.setRawClasspath(entries, new SubProgressMonitor(monitor, 1));
} catch (JavaModelException ex) {
Logger.getLogger().logError(ex);
}
}
}