blob: 052cdca57b9a3ae7608e9a7829b56388eee687f3 [file] [log] [blame]
/*********************************************************************
* Copyright (c) 2009 - 2012 SpringSource, a division of VMware, Inc.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
package org.eclipse.virgo.ide.manifest.core;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Writer;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Dictionary;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IPathVariableManager;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jst.j2ee.web.componentcore.util.WebArtifactEdit;
import org.eclipse.osgi.util.ManifestElement;
import org.eclipse.virgo.ide.facet.core.FacetCorePlugin;
import org.eclipse.virgo.ide.facet.core.FacetUtils;
import org.eclipse.virgo.ide.manifest.internal.core.model.BundleManifestHeader;
import org.eclipse.virgo.ide.module.core.ServerModuleDelegate;
import org.eclipse.virgo.util.osgi.manifest.BundleManifest;
import org.eclipse.virgo.util.osgi.manifest.BundleManifestFactory;
import org.eclipse.wst.common.project.facet.core.FacetedProjectFramework;
import org.osgi.framework.Constants;
/**
* Helper methods to located and load {@link BundleManifest} instances.
*
* @author Christian Dupuis
* @author Steffen Pingel
* @author Martin Lippert
* @since 1.0.0
*/
public class BundleManifestUtils {
/** URL file schema */
private static final String FILE_SCHEME = "file";
/**
* Returns a {@link BundleManifest} instance for the given <code>javaProject</code>.
* <p>
* This implementation searches the source folders of the {@link IJavaProject} and returns the first found
* META-INF/MANIFEST.MF as the valid manifest.
*/
public static BundleManifest getBundleManifest(IJavaProject javaProject, boolean testBundle) {
IFile manifestFile = locateManifest(javaProject, testBundle);
if (manifestFile != null) {
try {
return BundleManifestFactory.createBundleManifest(new InputStreamReader(manifestFile.getContents(true)));
} catch (Exception e) {
}
}
return null;
}
/**
* Locates the {@link IResource} representing the MANIFEST.MF of a <code>javaProject</code>.
* <p>
* This implementation searches the source folders of the {@link IJavaProject} and returns the first found
* META-INF/MANIFEST.MF as the valid manifest.
*/
public static IFile locateManifest(IJavaProject javaProject, boolean testBundle) {
String manifestLocation = testBundle ? BundleManifestCorePlugin.TEST_MANIFEST_FILE_LOCATION : BundleManifestCorePlugin.MANIFEST_FILE_LOCATION;
try {
for (IClasspathEntry entry : ServerModuleDelegate.getSourceClasspathEntries(javaProject.getProject(), testBundle)) {
IPath path = entry.getPath().append(manifestLocation).removeFirstSegments(1);
IFile manifestFileHandle = javaProject.getProject().getFile(path);
if (manifestFileHandle.exists()) {
return manifestFileHandle;
}
}
if (FacetedProjectFramework.hasProjectFacet(javaProject.getProject(), FacetCorePlugin.WEB_FACET_ID)) {
WebArtifactEdit webArtifact = WebArtifactEdit.getWebArtifactEditForRead(javaProject.getProject());
if (webArtifact != null) {
IPath webDotXmlPath = webArtifact.getDeploymentDescriptorPath();
if (webDotXmlPath != null) {
IPath path = webDotXmlPath.removeLastSegments(2).append(manifestLocation).removeFirstSegments(1);
IFile manifestFileHandle = javaProject.getProject().getFile(path);
if (manifestFileHandle.exists()) {
return manifestFileHandle;
}
}
}
}
} catch (Exception e) {
}
return null;
}
/**
* Returns a full qualified location of the META-INF folder.
* <p>
* This implementation searches the source folders of the {@link IJavaProject} and returns the first found
* META-INF/MANIFEST.MF as the valid manifest.
*/
public static String locateManifestFolder(IJavaProject javaProject) {
IResource resource = locateManifest(javaProject, false);
if (resource != null) {
IContainer container = resource.getParent().getParent();
IPath location = container.getRawLocation();
if (location != null) {
return location.toString();
}
}
return null;
}
/**
* Returns a {@link File} instance for the given <code>javaProject</code>.
* <p>
* This implementation searches the source folders of the {@link IJavaProject} and returns the first found
* META-INF/MANIFEST.MF as the valid manifest.
*/
public static File locateManifestFile(IJavaProject javaProject, boolean testBundle) {
IResource resource = locateManifest(javaProject, testBundle);
if (resource != null) {
URI uri = convertResourceToUrl(resource);
if (uri != null) {
return new File(uri);
}
}
return null;
}
/**
* Converts a given {@link IResource} into a full qualified {@link URI} honoring eventual used Eclipse variables in
* the path expression.
*/
private static URI convertResourceToUrl(IResource resource) {
if (resource != null) {
URI uri = resource.getRawLocationURI();
if (uri != null) {
String scheme = uri.getScheme();
if (FILE_SCHEME.equalsIgnoreCase(scheme)) {
return uri;
} else if ("sourcecontrol".equals(scheme)) {
// special case of Rational Team Concert
IPath path = resource.getLocation();
File file = path.toFile();
if (file.exists()) {
return file.toURI();
}
} else {
IPathVariableManager variableManager = ResourcesPlugin.getWorkspace().getPathVariableManager();
return variableManager.resolveURI(uri);
}
}
}
return null;
}
/**
* Finds a {@link IResource} identified by a given <code>path</code> in the given <code>project</code>
*/
private static IResource findResource(IProject project, IPath path) {
if (path != null && project != null && path.removeFirstSegments(1) != null) {
return project.findMember(path.removeFirstSegments(1));
}
return null;
}
/**
* Dumps a new MANIFEST.MF into the given {@link IJavaProject}.
*/
public static void createNewBundleManifest(IJavaProject javaProject, String symbolicName, String bundleVersion, String providerName,
String bundleName, String serverModule, Map<String, String> properties) {
BundleManifest manifest = null;
File existingManifestFile = locateManifestFile(javaProject, false);
if (existingManifestFile != null) {
FileReader reader = null;
try {
reader = new FileReader(existingManifestFile);
manifest = BundleManifestFactory.createBundleManifest(new FileReader(existingManifestFile));
} catch (FileNotFoundException e) {
} catch (IOException e) {
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
}
}
}
} else {
manifest = BundleManifestFactory.createBundleManifest();
}
manifest.setBundleManifestVersion(2);
Dictionary<String, String> dictonary = manifest.toDictionary();
if (StringUtils.isNotBlank(symbolicName)) {
dictonary.put(Constants.BUNDLE_SYMBOLICNAME, symbolicName);
}
if (StringUtils.isNotBlank(bundleVersion)) {
dictonary.put(Constants.BUNDLE_VERSION, bundleVersion);
}
if (StringUtils.isNotBlank(bundleName)) {
dictonary.put(Constants.BUNDLE_NAME, bundleName);
}
if (StringUtils.isNotBlank(providerName)) {
dictonary.put(Constants.BUNDLE_DESCRIPTION, providerName);
}
for (Map.Entry<String, String> entry : properties.entrySet()) {
if (StringUtils.isNotEmpty(entry.getValue()) && StringUtils.isNotEmpty(entry.getKey())) {
dictonary.put(entry.getKey(), entry.getValue());
}
}
Writer writer = null;
try {
if (existingManifestFile != null) {
writer = new FileWriter(existingManifestFile);
} else {
writer = new FileWriter(getFirstPossibleManifestFile(javaProject.getProject(), false).getRawLocation().toFile());
}
BundleManifest bundleManifest = BundleManifestFactory.createBundleManifest(dictonary);
bundleManifest.write(writer);
} catch (IOException e) {
} finally {
if (writer != null) {
try {
writer.flush();
writer.close();
} catch (IOException e) {
}
}
}
}
public static void createNewParManifest(IProject project, String symbolicName, String version, String name, String description) {
Dictionary<String, String> manifest = BundleManifestFactory.createBundleManifest().toDictionary();
if (StringUtils.isNotBlank(symbolicName)) {
manifest.put("Application-SymbolicName", symbolicName);
}
if (StringUtils.isNotBlank(version)) {
manifest.put("Application-Version", version);
}
if (StringUtils.isNotBlank(name)) {
manifest.put("Application-Name", name);
}
if (StringUtils.isNotBlank(description)) {
manifest.put("Application-Description", description);
}
Writer writer = null;
try {
writer = new FileWriter(getFirstPossibleManifestFile(project, false).getRawLocation().toFile());
BundleManifest bundleManifest = BundleManifestFactory.createBundleManifest(manifest);
bundleManifest.write(writer);
} catch (IOException e) {
} finally {
if (writer != null) {
try {
writer.flush();
writer.close();
} catch (IOException e) {
}
}
}
}
public static IFile getFirstPossibleManifestFile(final IProject project, boolean isTestManifest) {
try {
if (FacetUtils.hasNature(project, JavaCore.NATURE_ID)) {
List<IClasspathEntry> entries = new ArrayList<IClasspathEntry>(
ServerModuleDelegate.getSourceClasspathEntries(project, isTestManifest));
Collections.sort(entries, new Comparator<IClasspathEntry>() {
public int compare(IClasspathEntry o1, IClasspathEntry o2) {
String s1 = o1.getPath().toString();
String s2 = o2.getPath().toString();
if (("/" + project.getName() + "/src/main/resources").equals(s1)) {
return -1;
} else if (("/" + project.getName() + "/src/test/resources").equals(s1)) {
return -1;
}
if (("/" + project.getName() + "/src/main/resources").equals(s2)) {
return 1;
} else if (("/" + project.getName() + "/src/test/resources").equals(s2)) {
return 1;
}
return s1.compareTo(s2);
}
});
for (IClasspathEntry entry : entries) {
return createNewManifestInFolder(findResource(project, entry.getPath()), isTestManifest);
}
} else {
return createNewManifestInFolder(project, isTestManifest);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static IFile createNewManifestInFolder(IResource resource, boolean isTestManifest) throws CoreException {
String manifestFilePath = "META-INF/"
+ (isTestManifest ? BundleManifestCorePlugin.TEST_MANIFEST_FILE_NAME : BundleManifestCorePlugin.MANIFEST_FILE_NAME);
IFile manifestFile = null;
if (resource instanceof IFolder) {
manifestFile = ((IFolder) resource).getFile(manifestFilePath);
} else if (resource instanceof IProject) {
manifestFile = ((IProject) resource).getFile(manifestFilePath);
}
if (manifestFile != null && !manifestFile.exists()) {
if (!manifestFile.getParent().exists()) {
((IFolder) manifestFile.getParent()).create(true, true, new NullProgressMonitor());
}
manifestFile.create(new ByteArrayInputStream("Manifest-Version: 1.0".getBytes()), true, new NullProgressMonitor());
}
return manifestFile;
}
public static int getLineNumber(IDocument document, BundleManifestHeader header, String valueSubstring) {
// make sure that we have a line number in case the bundle model is crashed
if (header == null) {
return 0;
}
for (int l = header.getLineNumber(); l < header.getLineNumber() + header.getLinesSpan(); l++) {
try {
IRegion lineRegion = document.getLineInformation(l);
String lineStr = document.get(lineRegion.getOffset(), lineRegion.getLength());
if (lineStr.indexOf(valueSubstring) >= 0) {
return l + 1;
}
} catch (BadLocationException ble) {
}
}
// it might span multiple lines, try a longer algorithm
try {
IRegion lineRegion = document.getLineInformation(header.getLineNumber());
String lineStr = document.get(lineRegion.getOffset(), lineRegion.getLength());
for (int l = header.getLineNumber() + 1; l < header.getLineNumber() + header.getLinesSpan(); l++) {
lineRegion = document.getLineInformation(l);
lineStr += document.get(lineRegion.getOffset() + 1/* the space */, lineRegion.getLength());
if (lineStr.indexOf(valueSubstring) >= 0) {
return l;
}
}
} catch (BadLocationException ble) {
}
return header.getLineNumber() + 1;
}
public static int getPackageLineNumber(IDocument document, BundleManifestHeader header, ManifestElement element) {
String packageName = element.getValue();
if (element.getDirectiveKeys() != null || element.getKeys() != null) {
return getLineNumber(document, header, packageName + ";");
}
// check for this exact package on the last line
try {
IRegion lineRegion = document.getLineInformation(header.getLineNumber() + header.getLinesSpan() - 1);
String lineStr = document.get(lineRegion.getOffset(), lineRegion.getLength());
if (lineStr.endsWith(packageName)) {
return header.getLineNumber() + header.getLinesSpan();
}
} catch (BadLocationException ble) {
}
// search all except last line
return getLineNumber(document, header, packageName + ",");
}
}