/******************************************************************************* | |
* 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); | |
} | |
} |