/********************************************************************** * Copyright (c) 2005-2009 ant4eclipse project team. * * 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: * Nils Hartmann, Daniel Kasmeroglu, Gerd Wuetherich **********************************************************************/ package org.ant4eclipse.lib.pde.tools; import java.io.File; import java.util.LinkedList; import java.util.List; import org.ant4eclipse.lib.core.Assure; import org.ant4eclipse.lib.core.exception.Ant4EclipseException; import org.ant4eclipse.lib.core.logging.A4ELogging; import org.ant4eclipse.lib.core.osgi.BundleLayoutResolver; import org.ant4eclipse.lib.core.service.ServiceRegistryAccess; import org.ant4eclipse.lib.core.util.Utilities; import org.ant4eclipse.lib.jdt.model.ClasspathEntry; import org.ant4eclipse.lib.jdt.tools.ResolvedClasspathEntry; import org.ant4eclipse.lib.jdt.tools.container.ClasspathContainerResolver; import org.ant4eclipse.lib.jdt.tools.container.ClasspathResolverContext; import org.ant4eclipse.lib.jdt.tools.container.JdtClasspathContainerArgument; import org.ant4eclipse.lib.pde.PdeExceptionCode; import org.ant4eclipse.lib.pde.internal.tools.BundleDependenciesResolver; import org.ant4eclipse.lib.pde.internal.tools.BundleDependenciesResolver.BundleDependency; import org.ant4eclipse.lib.pde.internal.tools.TargetPlatformImpl; import org.ant4eclipse.lib.pde.internal.tools.UnresolvedBundleException; import org.ant4eclipse.lib.pde.model.buildproperties.PluginBuildProperties; import org.ant4eclipse.lib.pde.model.pluginproject.BundleSource; import org.ant4eclipse.lib.pde.model.pluginproject.PluginProjectRole; import org.ant4eclipse.lib.platform.model.resource.EclipseProject; import org.eclipse.osgi.service.resolver.BundleDescription; /** * <p> * {@link ClasspathContainerResolver} for resolving the 'org.eclipse.pde.core.requiredPlugins' container. * </p> * * @author Gerd Wütherich (gerd@gerd-wuetherich.de) */ public class RequiredPluginsResolver implements ClasspathContainerResolver { /** * the constant for the container type 'org.eclipse.pde.core.requiredPlugins' */ public static final String CONTAINER_TYPE_PDE_REQUIRED_PLUGINS = "org.eclipse.pde.core.requiredPlugins"; /** * {@inheritDoc} */ public boolean canResolveContainer(ClasspathEntry classpathEntry) { return classpathEntry.getPath().startsWith(CONTAINER_TYPE_PDE_REQUIRED_PLUGINS); } /** * {@inheritDoc} * * @throws UnresolvedBundleException */ public void resolveContainer(ClasspathEntry classpathEntry, ClasspathResolverContext context) { Assure.notNull("context", context); // Step 1: get the plug-in project role EclipseProject eclipseProject = context.getCurrentProject(); PluginProjectRole pluginProjectRole = eclipseProject.getRole(PluginProjectRole.class); // Step 2: get the bundle description BundleDescription pluginProjectDescription = pluginProjectRole.getBundleDescription(); // Step 3: get the target platform TargetPlatform targetPlatform = getTargetPlatform(context); // Step 5: resolve the bundle dependencies BundleDescription resolvedBundleDescription = targetPlatform.getResolvedBundle( pluginProjectDescription.getSymbolicName(), pluginProjectDescription.getVersion()); resolveBundleClassPath(context, resolvedBundleDescription, targetPlatform); // Step 7: if the plug-in project is a fragment, we have to add the // host as well if (BundleDependenciesResolver.isFragment(resolvedBundleDescription)) { // Step 7.1: get the host description BundleDescription hostDescription; try { hostDescription = BundleDependenciesResolver.getHost(resolvedBundleDescription); } catch (UnresolvedBundleException e) { throw newBundleNotResolvedException(e, targetPlatform); } // resolveBundleClassPath(context, hostDescription); // Step 7.2: get the bundle source BundleSource bundleSource = (BundleSource) hostDescription.getUserObject(); // Step 7.3: add the bundle source to the context if (bundleSource.isEclipseProject()) { context.addReferencedProjects(bundleSource.getAsEclipseProject()); } // get the layout resolver for the host and add the host's class // path // entries to the class path BundleLayoutResolver hostLayoutResolver = BundleDependenciesResolver.getBundleLayoutResolver(hostDescription); File[] hostClasspathEntries = hostLayoutResolver.resolveBundleClasspathEntries(); context.addClasspathEntry(new ResolvedClasspathEntry(hostClasspathEntries)); } } /** * <p> * Resolves the bundle class path. * </p> * * @param context * @param resolvedBundleDescription * @param targetPlatform */ private void resolveBundleClassPath(ClasspathResolverContext context, BundleDescription resolvedBundleDescription, TargetPlatform targetPlatform) { // declare the bundle dependencies List<BundleDependency> bundleDependencies = null; try { String[] additionalBundles = null; if (context.hasCurrentProject()) { EclipseProject eclipseProject = context.getCurrentProject(); PluginProjectRole role = eclipseProject.getRole(PluginProjectRole.class); PluginBuildProperties buildProperties = role.getBuildProperties(); if (buildProperties == null) { // TODO should we fail here? A4ELogging.warn("No build.properties found in project '%s'", eclipseProject.getFolder()); } else { additionalBundles = buildProperties.getAdditionalBundles(); } } bundleDependencies = new BundleDependenciesResolver().resolveBundleClasspath(resolvedBundleDescription, targetPlatform, additionalBundles); if (context.isRuntime()) { // add dependent bundles List<BundleDependency> dependencies = new LinkedList<BundleDependenciesResolver.BundleDependency>( bundleDependencies); for (BundleDependency dependency : dependencies) { addDependentBundles(dependency, bundleDependencies); } } } catch (UnresolvedBundleException e) { throw newBundleNotResolvedException(e, targetPlatform); } // add all dependencies to the class path for (BundleDependency bundleDependency : bundleDependencies) { // add the referenced eclipse projects - this information is needed // to compute the correct build order List<EclipseProject> referencedPluginProjects = bundleDependency.getReferencedPluginProjects(); for (EclipseProject referencedPluginProject : referencedPluginProjects) { context.addReferencedProjects(referencedPluginProject); } // add the class path entries - these entries are used for the class // path context.addClasspathEntry(bundleDependency.getResolvedClasspathEntry()); } // // add the host to the class path // if (BundleDependenciesResolver.isFragment(resolvedBundleDescription)) { // // // // BundleDescription host = BundleDependenciesResolver.getHost(resolvedBundleDescription); // // BundleLayoutResolver layoutResolver = BundleDependenciesResolver.getBundleLayoutResolver(host); // // // ResolvedClasspathEntry entry = new ResolvedClasspathEntry(layoutResolver.resolveBundleClasspathEntries()); // // // // context.addClasspathEntry(entry); // } // STEP 2: add the host... // if (BundleDependenciesResolver.isFragment(resolvedBundleDescription)) // { // // // STEP 2.1: get the host // BundleDescription host = BundleDependenciesResolver // .getHost(resolvedBundleDescription); // // // add the host bundle // BundleLayoutResolver layoutResolver = BundleDependenciesResolver // .getBundleLayoutResolver(host); // ResolvedClasspathEntry entry = new ResolvedClasspathEntry( // layoutResolver.resolveBundleClasspathEntries()); // context.addClasspathEntry(entry); // // // STEP 2.2: // try { // bundleDependencies = new BundleDependenciesResolver() // .resolveBundleClasspath(host); // } catch (UnresolvedBundleException e) { // // // try to find the root cause // BundleDescription description = new UnresolvedBundlesAnalyzer( // targetPlatform).getRootCause(e.getBundleDescription()); // // // throw a BUNDLE_NOT_RESOLVED_EXCEPTION // throw new Ant4EclipseException( // PdeExceptionCode.BUNDLE_NOT_RESOLVED_EXCEPTION, // TargetPlatformImpl // .dumpResolverErrors(description, true)); // } // // // add all dependencies to the class path // for (BundleDependency bundleDependency : bundleDependencies) { // // // add the referenced eclipse projects - this information is // // needed to compute the correct build order // List<EclipseProject> referencedPluginProjects = bundleDependency // .getReferencedPluginProjects(); // for (EclipseProject referencedPluginProject : // referencedPluginProjects) { // context.addReferencedProjects(referencedPluginProject); // } // // // add the class path entries - these entries are used for the // // class path // context.addClasspathEntry(bundleDependency // .getResolvedClasspathEntry()); // } // } } private Ant4EclipseException newBundleNotResolvedException(UnresolvedBundleException e, TargetPlatform targetPlatform) { // try to find the root cause // BundleDescription description = new UnresolvedBundlesAnalyzer(targetPlatform) // .getRootCause(e.getBundleDescription()); // throw a BUNDLE_NOT_RESOLVED_EXCEPTION return new Ant4EclipseException(PdeExceptionCode.BUNDLE_NOT_RESOLVED_EXCEPTION, TargetPlatformImpl.dumpResolverErrors(new BundleDescription[] { e.getBundleDescription() }, true)); } private void addDependentBundles(BundleDependency referencedBundle, List<BundleDependency> bundleDependencies) throws UnresolvedBundleException { // Get the dependencies of the bundle List<BundleDependency> dependentBundleDependencies = new BundleDependenciesResolver() .resolveBundleClasspath(referencedBundle.getHost()); // Add all dependencies of the bundle to the result list for (BundleDependency bundleDependency : dependentBundleDependencies) { if (!bundleDependencies.contains(bundleDependency)) { bundleDependencies.add(bundleDependency); // add the dependencies addDependentBundles(bundleDependency, bundleDependencies); } } } /** * <p> * Returns the target platform. * </p> * * @param context * the context * @return the target platform. */ private TargetPlatform getTargetPlatform(ClasspathResolverContext context) { // get the TargetPlatform TargetPlatformRegistry registry = ServiceRegistryAccess.instance().getService(TargetPlatformRegistry.class); // get the container arguments JdtClasspathContainerArgument targetPlatformContainerArgument = context .getJdtClasspathContainerArgument("targetPlatformId"); JdtClasspathContainerArgument platformConfigurationIdContainerArgument = context .getJdtClasspathContainerArgument("platformConfigurationId"); // get the platform configuration PlatformConfiguration configuration = null; if (platformConfigurationIdContainerArgument != null) { String platformConfigurationId = platformConfigurationIdContainerArgument.getValue(); if (Utilities.hasText(platformConfigurationId)) { configuration = registry.getPlatformConfiguration(platformConfigurationId); if (configuration == null) { throw new Ant4EclipseException(PdeExceptionCode.UKNOWN_PLATFORM_CONFIGURATION, platformConfigurationId); } } } if (configuration == null) { configuration = new PlatformConfiguration(); } if (targetPlatformContainerArgument == null) { // get the one and only target platform if (registry.getTargetPlatformDefinitionIds().size() == 1) { String id = registry.getTargetPlatformDefinitionIds().get(0); return registry.getInstance(context.getWorkspace(), id, configuration); } // throw new Ant4EclipseException throw new Ant4EclipseException(PdeExceptionCode.NO_TARGET_PLATFORM_SET); } else { // get the TargetPlatform return registry.getInstance(context.getWorkspace(), targetPlatformContainerArgument.getValue(), configuration); } } }