blob: 1f8d966db17225aae2946baf421e3a4fb3ac6450 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2011 SAP AG 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:
* Kaloyan Raev (SAP AG) - initial API and implementation
*******************************************************************************/
package org.eclipse.libra.facet;
import static org.eclipse.libra.facet.OSGiBundleFacetUtils.BUILD_PROPERTIES;
import static org.eclipse.libra.facet.OSGiBundleFacetUtils.JAVAX_EL_PACKAGE;
import static org.eclipse.libra.facet.OSGiBundleFacetUtils.JAVAX_PERSISTENCE_PACKAGE;
import static org.eclipse.libra.facet.OSGiBundleFacetUtils.JAVAX_SERVLET_HTTP_PACKAGE;
import static org.eclipse.libra.facet.OSGiBundleFacetUtils.JAVAX_SERVLET_JSP_EL_PACKAGE;
import static org.eclipse.libra.facet.OSGiBundleFacetUtils.JAVAX_SERVLET_JSP_PACKAGE;
import static org.eclipse.libra.facet.OSGiBundleFacetUtils.JAVAX_SERVLET_JSP_TAGEXT_PACKAGE;
import static org.eclipse.libra.facet.OSGiBundleFacetUtils.JAVAX_SERVLET_PACKAGE;
import static org.eclipse.libra.facet.OSGiBundleFacetUtils.JAVA_FACET;
import static org.eclipse.libra.facet.OSGiBundleFacetUtils.JPA_FACET;
import static org.eclipse.libra.facet.OSGiBundleFacetUtils.META_INF;
import static org.eclipse.libra.facet.OSGiBundleFacetUtils.META_PERSISTENCE_HEADER;
import static org.eclipse.libra.facet.OSGiBundleFacetUtils.REQUIRED_PLUGINS_CONTAINER_PATH;
import static org.eclipse.libra.facet.OSGiBundleFacetUtils.WEB_CONTEXT_PATH_HEADER;
import static org.eclipse.libra.facet.OSGiBundleFacetUtils.WEB_INF_CLASSES;
import static org.eclipse.libra.facet.OSGiBundleFacetUtils.getBundleProjectDescription;
import static org.eclipse.libra.facet.OSGiBundleFacetUtils.getContextRootFromWTPModel;
import static org.eclipse.libra.facet.OSGiBundleFacetUtils.getWebContentPath;
import static org.eclipse.libra.facet.OSGiBundleFacetUtils.hasPluginNature;
import static org.eclipse.libra.facet.OSGiBundleFacetUtils.hasRequiredPlugins;
import static org.eclipse.libra.facet.OSGiBundleFacetUtils.isJavaProject;
import static org.eclipse.libra.facet.OSGiBundleFacetUtils.isJpaProject;
import static org.eclipse.libra.facet.OSGiBundleFacetUtils.isWebProject;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jst.common.project.facet.core.internal.JavaFacetUtil;
import org.eclipse.libra.facet.internal.LibraFacetPlugin;
import org.eclipse.osgi.service.resolver.VersionRange;
import org.eclipse.pde.core.project.IBundleClasspathEntry;
import org.eclipse.pde.core.project.IBundleProjectDescription;
import org.eclipse.pde.core.project.IBundleProjectService;
import org.eclipse.pde.core.project.IPackageExportDescription;
import org.eclipse.pde.core.project.IPackageImportDescription;
import org.eclipse.wst.common.componentcore.ComponentCore;
import org.eclipse.wst.common.componentcore.internal.util.FacetedProjectUtilities;
import org.eclipse.wst.common.componentcore.resources.IVirtualComponent;
import org.eclipse.wst.common.componentcore.resources.IVirtualReference;
import org.eclipse.wst.common.project.facet.core.IDelegate;
import org.eclipse.wst.common.project.facet.core.IProjectFacetVersion;
import org.osgi.framework.Version;
public class OSGiBundleFacetInstallDelegate implements IDelegate {
public void execute(IProject project, IProjectFacetVersion fv,
Object configObject, IProgressMonitor monitor) throws CoreException {
OSGiBundleFacetInstallConfig config = (OSGiBundleFacetInstallConfig) configObject;
doExecute(project, config, monitor);
}
private static void doExecute(IProject project,
OSGiBundleFacetInstallConfig config, IProgressMonitor monitor)
throws CoreException {
setBundleRoot(project);
createBundleProjectDescription(project, config, monitor);
addRequiredPluginsClasspathContainer(project, monitor);
if (isJpaProject(project)) {
moveMetaInfToRoot(project, monitor);
}
}
private static void setBundleRoot(IProject project) throws CoreException {
IPath bundleRoot = null;
if (isWebProject(project)) {
bundleRoot = getWebContentPath(project);
}
if (bundleRoot != null) {
IBundleProjectService bundleProjectService = LibraFacetPlugin.getDefault().getBundleProjectService();
bundleProjectService.setBundleRoot(project, bundleRoot);
}
}
private static void createBundleProjectDescription(IProject project,
OSGiBundleFacetInstallConfig config, IProgressMonitor monitor)
throws CoreException {
IBundleProjectDescription bundleProjectDescription = getBundleProjectDescription(project);
bundleProjectDescription.setSymbolicName(config.getSymbolicName());
bundleProjectDescription.setBundleVersion(config.getVersion());
String bundleName = config.getName();
if (bundleName != null && bundleName.trim().length() > 0) {
bundleProjectDescription.setBundleName(bundleName);
}
String bundleVendor = config.getVendor();
if (bundleVendor != null && bundleVendor.trim().length() > 0) {
bundleProjectDescription.setBundleVendor(bundleVendor);
}
bundleProjectDescription.setEquinox(true);
bundleProjectDescription.setExtensionRegistry(false);
bundleProjectDescription.setNatureIds(getNatureIds(bundleProjectDescription));
bundleProjectDescription.setLaunchShortcuts(getLaunchShortcuts(project));
Map<String, String> headers = getAdditionalHeaders(config, project);
for (Map.Entry<String, String> entry : headers.entrySet()) {
bundleProjectDescription.setHeader(entry.getKey(), entry.getValue());
}
bundleProjectDescription.setPackageExports(getPackageExports(project));
bundleProjectDescription.setPackageImports(getPackageImports(bundleProjectDescription));
bundleProjectDescription.setBinIncludes(getBinIncludes(bundleProjectDescription));
bundleProjectDescription.setBundleClasspath(getBundleClasspath(bundleProjectDescription));
setExecutionEnvironments(bundleProjectDescription);
bundleProjectDescription.apply(monitor);
}
private static String[] getNatureIds(IBundleProjectDescription bundleProjectDescription) {
String[] natureIds = bundleProjectDescription.getNatureIds();
String[] newNatureIds = new String[natureIds.length + 1];
for (int i = 0; i < natureIds.length; i++) {
newNatureIds[i] = natureIds[i];
}
newNatureIds[newNatureIds.length - 1] = IBundleProjectDescription.PLUGIN_NATURE;
return newNatureIds;
}
private static String[] getLaunchShortcuts(IProject project) throws CoreException {
if (isWebProject(project)) {
return new String[] {
"org.eclipse.pde.ui.EquinoxLaunchShortcut", //$NON-NLS-1$
"org.eclipse.wst.server.launchShortcut" //$NON-NLS-1$
};
}
// use default OSGi Framework launchers
return null;
}
private static Map<String, String> getAdditionalHeaders(OSGiBundleFacetInstallConfig config, IProject project) throws CoreException {
Map<String, String> headers = new HashMap<String, String>();
if (isWebProject(project)) {
// check if there is existing Web-ContextPath header in the manifest
if (config.getHeaders().containsKey(WEB_CONTEXT_PATH_HEADER)) {
// overwrite the context path in the WTP model with the one value from the OSGi header
headers.put(WEB_CONTEXT_PATH_HEADER, config.getHeaders().get(WEB_CONTEXT_PATH_HEADER));
} else {
// use the context path from the WTP model
headers.put(WEB_CONTEXT_PATH_HEADER, getContextRootFromWTPModel(project));
}
}
if (isJpaProject(project)) {
headers.put(META_PERSISTENCE_HEADER, ""); //$NON-NLS-1$
}
return headers;
}
private static IPackageExportDescription[] getPackageExports(IProject project) throws CoreException {
IBundleProjectService bundleProjectService = LibraFacetPlugin.getDefault().getBundleProjectService();
List<IPackageExportDescription> list = new ArrayList<IPackageExportDescription>();
if (isJavaProject(project)) {
IJavaProject javaProject = JavaCore.create(project);
IPackageFragmentRoot[] fragmentRoots = javaProject.getAllPackageFragmentRoots();
for (IPackageFragmentRoot fragmentRoot : fragmentRoots) {
if (fragmentRoot.getKind() == IPackageFragmentRoot.K_SOURCE && fragmentRoot.getParent().equals(javaProject)) {
IJavaElement[] elements = fragmentRoot.getChildren();
for (IJavaElement element : elements) {
IPackageFragment fragment = (IPackageFragment) element;
if (fragment.containsJavaResources()) {
list.add(bundleProjectService.newPackageExport(fragment.getElementName(), null, true, null));
}
}
}
}
}
return list.toArray(new IPackageExportDescription[list.size()]);
}
private static IPackageImportDescription[] getPackageImports(IBundleProjectDescription bundleProjectDescription) throws CoreException {
IProject project = bundleProjectDescription.getProject();
Map<String, IPackageImportDescription> packages = new TreeMap<String, IPackageImportDescription>();
// look for existing package imports
IPackageImportDescription[] imports = bundleProjectDescription.getPackageImports();
if (imports != null) {
for (IPackageImportDescription imp : imports) {
packages.put(imp.getName(), imp);
}
}
if (isWebProject(project)) {
// add the most popular servlet packages
addPackageImport(packages, JAVAX_SERVLET_PACKAGE, null, false);
addPackageImport(packages, JAVAX_SERVLET_HTTP_PACKAGE, null, false);
addPackageImport(packages, JAVAX_SERVLET_JSP_PACKAGE, null, false);
addPackageImport(packages, JAVAX_SERVLET_JSP_EL_PACKAGE, null, false);
addPackageImport(packages, JAVAX_SERVLET_JSP_TAGEXT_PACKAGE, null, false);
addPackageImport(packages, JAVAX_EL_PACKAGE, null, false);
// add packages exported by referenced components
IVirtualComponent component = ComponentCore.createComponent(project);
IVirtualReference[] references = component.getReferences();
for (IVirtualReference ref : references) {
IProject refProject = ref.getReferencedComponent().getProject();
if (refProject != null && refProject != project && hasPluginNature(refProject)) {
IPackageExportDescription[] exports = getBundleProjectDescription(refProject).getPackageExports();
for (IPackageExportDescription export : exports) {
String importName = export.getName();
Version exportVersion = export.getVersion();
VersionRange range = (exportVersion == null) ? null : new VersionRange(exportVersion.toString());
addPackageImport(packages, importName, range, false);
}
}
}
}
if (isJpaProject(project)) {
String version = FacetedProjectUtilities.getProjectFacetVersion(project, JPA_FACET).getVersionString();
addPackageImport(packages, String.format(JAVAX_PERSISTENCE_PACKAGE, version), null, false);
}
return packages.values().toArray(new IPackageImportDescription[packages.size()]);
}
private static void addPackageImport(Map<String, IPackageImportDescription> packages, String importName, VersionRange range, boolean optional) {
IBundleProjectService bundleProjectService = LibraFacetPlugin.getDefault().getBundleProjectService();
if (!packages.containsKey(importName)) {
IPackageImportDescription imp = bundleProjectService.newPackageImport(importName, range, optional);
packages.put(importName, imp);
}
}
private static IPath[] getBinIncludes(IBundleProjectDescription bundleProjectDescription) throws CoreException {
IProject project = bundleProjectDescription.getProject();
IVirtualComponent component = ComponentCore.createComponent(project);
if (isWebProject(project)) {
IPath bundleRoot = component.getRootFolder().getProjectRelativePath();
IResource[] resources = project.getFolder(bundleRoot).members();
List<IPath> binPaths = new ArrayList<IPath>();
for (int i = 0; i < resources.length; i++) {
String token = resources[i].getName();
if (resources[i].getType() == IResource.FOLDER) {
token += '/';
}
if (!token.equals(BUILD_PROPERTIES)) {
binPaths.add(new Path(token));
}
}
return binPaths.toArray(new IPath[binPaths.size()]);
}
// don't modify bin.includes by default
return bundleProjectDescription.getBinIncludes();
}
private static IBundleClasspathEntry[] getBundleClasspath(IBundleProjectDescription bundleProjectDescription) throws CoreException {
IProject project = bundleProjectDescription.getProject();
IBundleClasspathEntry[] bundleClasspath = bundleProjectDescription.getBundleClasspath();
if (OSGiBundleFacetUtils.isJavaProject(project)) {
IJavaProject javaProject = JavaCore.create(project);
if (bundleClasspath == null || bundleClasspath.length == 0) {
IPath[] javaSourceFolderPaths = getJavaSourceFolderPaths(javaProject);
if (javaSourceFolderPaths != null && javaSourceFolderPaths.length > 0) {
IBundleProjectService bundleProjectService = LibraFacetPlugin.getDefault().getBundleProjectService();
List<IBundleClasspathEntry> bundleClasspathList = new ArrayList<IBundleClasspathEntry>();
IPath binary = getRelativePath(project, javaProject.getOutputLocation());
IPath library = (isWebProject(project))
? new Path(WEB_INF_CLASSES) // add WEB-INF/classes for WABs
: null; // add . for other OSGi bundles
// iterate over source folders and create IBundleClasspathEntry for each one.
for (IPath iPath : javaSourceFolderPaths) {
bundleClasspathList.add(bundleProjectService.newBundleClasspathEntry(
getRelativePath(project, iPath), binary, library));
}
bundleClasspath = bundleClasspathList.toArray(new IBundleClasspathEntry[] { });
}
} else {
// TODO
}
}
// don't modify bin.includes by default
return bundleClasspath;
}
private static void addRequiredPluginsClasspathContainer(IProject project, IProgressMonitor monitor) throws CoreException {
if (isJavaProject(project)) {
IJavaProject javaProject = JavaCore.create(project);
IClasspathEntry[] entries = javaProject.getRawClasspath();
if (!hasRequiredPlugins(entries)) {
IClasspathEntry[] newEntries = new IClasspathEntry[entries.length + 1];
System.arraycopy(entries, 0, newEntries, 0, entries.length);
newEntries[newEntries.length - 1] = JavaCore.newContainerEntry(REQUIRED_PLUGINS_CONTAINER_PATH);
javaProject.setRawClasspath(newEntries, monitor);
}
}
}
private static IPath[] getJavaSourceFolderPaths(IJavaProject javaProject) throws JavaModelException {
List<IPath> paths = new ArrayList<IPath>();
IPackageFragmentRoot[] fragmentRoots = javaProject.getAllPackageFragmentRoots();
for (IPackageFragmentRoot fragmentRoot : fragmentRoots) {
if (fragmentRoot.getKind() == IPackageFragmentRoot.K_SOURCE && fragmentRoot.getParent().equals(javaProject)) {
paths.add(fragmentRoot.getPath());
}
}
return paths.toArray(new IPath[paths.size()]);
}
private static IPath getRelativePath(IProject project, IPath path) {
return path.makeRelativeTo(project.getFullPath()).addTrailingSeparator();
}
private static void setExecutionEnvironments(IBundleProjectDescription bundleProjectDescription) {
IProject project = bundleProjectDescription.getProject();
IProjectFacetVersion javaProjectFacetVersion = FacetedProjectUtilities.getProjectFacetVersion(project, JAVA_FACET);
if (javaProjectFacetVersion != null) {
String[] existingEEs = bundleProjectDescription.getExecutionEnvironments();
String newEE = JavaFacetUtil.getCorrespondingExecutionEnvironment(javaProjectFacetVersion);
//if there are existing EEs different from newEE add newEE. Else just set newEE.
if (existingEEs != null) {
ArrayList<String> eeList = new ArrayList<String>(Arrays.asList(existingEEs));
if (!eeList.contains(newEE)) {
eeList.add(newEE);
bundleProjectDescription.setExecutionEnvironments(eeList.toArray(new String[eeList.size()]));
}
} else {
bundleProjectDescription.setExecutionEnvironments(new String[] { newEE } );
}
}
}
private static void moveMetaInfToRoot(IProject project, IProgressMonitor monitor) throws CoreException {
// find the first META-INF folder as a second-level folder
IFolder folder = null;
IResource[] resources = project.members();
for (IResource r : resources) {
if (r.getType() == IResource.FOLDER) {
IFolder f = (IFolder) r;
IResource metaInf = f.findMember(META_INF);
if (metaInf != null && metaInf.getType() == IResource.FOLDER) {
folder = (IFolder) metaInf;
break;
}
}
}
if (folder == null || !folder.exists())
return;
// copy all resources to /META-INF
IResource[] members = folder.members();
for (IResource member : members) {
IPath destination = project.getFolder(META_INF).getFullPath().append(member.getName());
if (!project.getWorkspace().getRoot().exists(destination)) { // this check is needed for the /src/MANIFEST.MF added by the jst.utility facet
member.move(destination, true, monitor);
}
}
folder.delete(true, monitor);
}
}