Project: ant4eclipse
package org.ant4eclipse.ant.pde;
 
import static org.ant4eclipse.lib.core.Assure.notNull; 
import static org.ant4eclipse.lib.core.logging.A4ELogging.warn; 
 
import org.ant4eclipse.ant.core.FileListHelper; 
import org.ant4eclipse.ant.platform.ExecuteLauncherTask; 
import org.ant4eclipse.ant.platform.core.MacroExecutionValues; 
import org.ant4eclipse.ant.platform.core.delegate.MacroExecutionValuesProvider; 
import org.ant4eclipse.lib.core.service.ServiceRegistryAccess; 
import org.ant4eclipse.lib.core.util.StringMap; 
import org.ant4eclipse.lib.core.util.Utilities; 
import org.ant4eclipse.lib.jdt.model.jre.JavaRuntime; 
import org.ant4eclipse.lib.jdt.model.jre.JavaRuntimeRegistry; 
import org.ant4eclipse.lib.pde.model.launcher.EquinoxLaunchConfigurationWrapper; 
import org.ant4eclipse.lib.pde.model.launcher.SelectedLaunchConfigurationBundle; 
import org.ant4eclipse.lib.pde.model.pluginproject.BundleSource; 
import org.ant4eclipse.lib.platform.model.launcher.LaunchConfiguration; 
import org.ant4eclipse.lib.platform.model.resource.EclipseProject; 
import org.apache.tools.ant.BuildException; 
import org.apache.tools.ant.taskdefs.MacroDef; 
import org.eclipse.osgi.service.resolver.BundleDescription; 
import org.osgi.framework.Version; 
 
import java.io.File; 
 
/**
 * Executes a Equinox Launch Configuration (type="org.eclipse.pde.ui.EquinoxLauncher") 
 *  
 * @author Nils Hartmann ([email protected]
 */
 
public class ExecuteEquinoxLauncherTask extends ExecuteLauncherTask implements TargetPlatformAwareComponent { 
 
  /**
   * The forEachBundle scope that is invoked for each bundle that is selected either from the workspace or the target 
   * platform 
   */
 
  public static final String          SCOPE_FOR_EACH_SELECTED_BUNDLE = "forEachSelectedBundle"
 
  /** - */ 
  private TargetPlatformAwareDelegate _targetPlatformAwareDelegate; 
 
  /**
   * Create new instance 
   */
 
  public ExecuteEquinoxLauncherTask() { 
    super("executeEquinoxLauncher"); 
 
    this._targetPlatformAwareDelegate = new TargetPlatformAwareDelegate(); 
  } 
 
  /**
   * {@inheritDoc} 
   */
 
  public String getPlatformConfigurationId() { 
    return this._targetPlatformAwareDelegate.getPlatformConfigurationId(); 
  } 
 
  /**
   * {@inheritDoc} 
   */
 
  public final String getTargetPlatformId() { 
    return this._targetPlatformAwareDelegate.getTargetPlatformId(); 
  } 
 
  /**
   * {@inheritDoc} 
   */
 
  public boolean isPlatformConfigurationIdSet() { 
    return this._targetPlatformAwareDelegate.isPlatformConfigurationIdSet(); 
  } 
 
  /**
   * {@inheritDoc} 
   */
 
  public final boolean isTargetPlatformIdSet() { 
    return this._targetPlatformAwareDelegate.isTargetPlatformIdSet(); 
  } 
 
  /**
   * {@inheritDoc} 
   */
 
  public void setPlatformConfigurationId(String platformConfigurationId) { 
    this._targetPlatformAwareDelegate.setPlatformConfigurationId(platformConfigurationId); 
  } 
 
  /**
   * {@inheritDoc} 
   */
 
  public final void setTargetPlatformId(String targetPlatformId) { 
    this._targetPlatformAwareDelegate.setTargetPlatformId(targetPlatformId); 
  } 
 
  /**
   * {@inheritDoc} 
   */
 
  public final void requireTargetPlatformIdSet() { 
    this._targetPlatformAwareDelegate.requireTargetPlatformIdSet(); 
  } 
 
  /**
   * Makes sure the selected launch configuration is a PDE-Launch Configuration 
   */
 
  @Override 
  protected void ensureSupportedLaunchConfiguration(LaunchConfiguration launchConfiguration) { 
    super.ensureSupportedLaunchConfiguration(launchConfiguration); 
 
    if (!EquinoxLaunchConfigurationWrapper.isEquinoxLaunchConfiguration(launchConfiguration)) { 
      throw new BuildException("The launch configuration you've specified must be a Equinox launch configuration"); 
    } 
  } 
 
  @Override 
  public Object createDynamicElement(String name) throws BuildException { 
    // handle 'forEachSelectedBundle' element 
    if (SCOPE_FOR_EACH_SELECTED_BUNDLE.equalsIgnoreCase(name)) { 
      return createScopedMacroDefinition(SCOPE_FOR_EACH_SELECTED_BUNDLE); 
    } 
 
    // all other scopes: not handled here, try super class 
    return super.createDynamicElement(name); 
  } 
 
  /**
   * Make sure all preconditions are fulfilled before executing the task 
   */
 
  @Override 
  protected void preconditions() throws BuildException { 
    super.preconditions(); 
 
    this._targetPlatformAwareDelegate.requireTargetPlatformIdSet(); 
  } 
 
  /**
   * Execute the scoped macro definitions 
   */
 
  @Override 
  protected void doExecute(String scope, MacroDef macroDef) { 
    if (SCOPE_FOR_EACH_SELECTED_BUNDLE.equals(scope)) { 
      executeForEachSelectedBundleScopedMacroDef(macroDef); 
    } else { 
      super.doExecute(scope, macroDef); 
    } 
  } 
 
  /**
   * Run the 'forEachSelectedBundle' macro 
   *  
   * @param macroDef 
   */
 
  private void executeForEachSelectedBundleScopedMacroDef(MacroDef macroDef) { 
 
    // Step 1: read the launchconfiguration file 
    final LaunchConfiguration launchConfiguration = getLaunchConfiguration(); 
 
    // Step 2: Create a EquinoxLaunchConfigurationWrapper to access Equinox-specific settings in launch config 
    EquinoxLaunchConfigurationWrapper wrapper = new EquinoxLaunchConfigurationWrapper(launchConfiguration); 
 
    // Step 3: Get all selected workspace bundles 
    final SelectedLaunchConfigurationBundle[] selectedWorkspaceBundles = wrapper.getSelectedWorkspaceBundles(); 
 
    // Step 3a: run the macro for each workspace bundle 
    for (SelectedLaunchConfigurationBundle selectedWorkspaceBundle : selectedWorkspaceBundles) { 
      executeMacroInstance(macroDef, createBundleMacroExecuteValuesProvider(wrapper, selectedWorkspaceBundle, true)); 
    } 
 
    // Step 4: Get all selected bundles from target platform 
    final SelectedLaunchConfigurationBundle[] selectedTargetBundles = wrapper.getSelectedTargetBundles(); 
 
    // Step 4a: Run the macro for each selected target platform bundle 
    for (SelectedLaunchConfigurationBundle selectedTargetBundle : selectedTargetBundles) { 
      executeMacroInstance(macroDef, createBundleMacroExecuteValuesProvider(wrapper, selectedTargetBundle, false)); 
    } 
 
  } 
 
  /**
   * Creates a {@link MacroExecutionValuesProvider} for the given selected bundle. 
   *  
   * <p> 
   * The providered that is returned contains all properties and references that should passed to the macro 
   *  
   * @param wrapper 
   * @param selectedBundle 
   * @param workspaceBundle 
   * @return 
   */
 
  protected MacroExecutionValuesProvider createBundleMacroExecuteValuesProvider
      final EquinoxLaunchConfigurationWrapper wrapper, final SelectedLaunchConfigurationBundle selectedBundle, 
      final boolean workspaceBundle) { 
    notNull("wrapper", wrapper); 
    notNull("launchConfigurationBundleInfo", selectedBundle); 
 
    final BundleDescription bundleDescription = getResolvedBundle(selectedBundle); 
 
    return new MacroExecutionValuesProvider() { 
      public MacroExecutionValues provideMacroExecutionValues(MacroExecutionValues values) { 
        values = provideDefaultMacroExecutionValues(values); 
 
        final StringMap properties = values.getProperties(); 
        properties.put("selectedBundle.symbolicName", selectedBundle.getBundleSymbolicName()); 
        String version = selectedBundle.hasVersion() ? selectedBundle.getVersion() : ""
        properties.put("selectedBundle.version", version); 
        properties.put("selectedBundle.startLevel", selectedBundle.getStartLevel()); 
        properties.put("selectedBundle.autoStart", selectedBundle.getAutoStart()); 
        properties.put("selectedBundle.workspaceBundle", Boolean.toString(workspaceBundle)); 
        properties.put("selectedBundle.targetBundle", Boolean.toString(!workspaceBundle)); 
        final String resolvedStartLevel = wrapper.getResolvedStartLevel(selectedBundle); 
        properties.put("selectedBundle.resolvedStartLevel", resolvedStartLevel); 
        final String resolvedAutoStart = wrapper.getResolvedAutoStart(selectedBundle); 
        properties.put("selectedBundle.resolvedAutoStart", resolvedAutoStart); 
 
        // set the "bundle start parameter" as expected in osgi.bundles property 
        String bundleStart = ""
        if (Utilities.hasText(resolvedStartLevel)) { 
          bundleStart = "@" + resolvedStartLevel; 
        } 
        if (Utilities.hasText(resolvedAutoStart)) { 
          if (Utilities.hasText(bundleStart)) { 
            bundleStart += ":" + resolvedAutoStart; 
          } else { 
            bundleStart = "@" + resolvedAutoStart; 
          } 
        } 
 
        properties.put("selectedBundle.startParameter", bundleStart); 
 
        if (bundleDescription != null) { 
          BundleSource bundlesource = (BundleSource) bundleDescription.getUserObject(); 
 
          properties.put("resolvedBundle.version", bundleDescription.getVersion().toString()); 
          properties.put("resolvedBundle.isSystemBundle", Boolean.toString(bundleDescription.getBundleId() == 0)); 
          if (bundlesource.isEclipseProject()) { 
            // Plug-in is a source project contained in the workspace 
            EclipseProject project = bundlesource.getAsEclipseProject(); 
            File location = project.getFolder(); 
            properties.put("resolvedBundle.isSource""true"); 
            properties.put("resolvedBundle.file", location.getAbsolutePath()); 
            properties.put("resolvedBundle.fileName", location.getName()); 
            properties.put("resolvedBundle.projectName", project.getSpecifiedName()); 
          } else { 
            // Bundle comes from the target platform 
            File location = bundlesource.getAsFile(); 
            properties.put("resolvedBundle.isSource""false"); 
            properties.put("resolvedBundle.file", location.getAbsolutePath()); 
            properties.put("resolvedBundle.fileName", location.getName()); 
            values.getReferences().put("resolvedBundle.fileList", FileListHelper.getFileList(location)); 
          } 
        } 
        return values; 
      } 
    }; 
  } 
 
  /**
   * Returns the resolved bundle from the target platform 
   *  
   * @param launchConfigurationBundleInfo 
   * @return the {@link BundleDescription} for the selected bundle or null if the bundle could not be resolved 
   */
 
  protected BundleDescription getResolvedBundle(SelectedLaunchConfigurationBundle launchConfigurationBundleInfo) { 
    String bundleSymbolicName = launchConfigurationBundleInfo.getBundleSymbolicName(); 
    Version osgiVersion = (launchConfigurationBundleInfo.hasVersion() ? new Version(launchConfigurationBundleInfo 
        .getVersion()) : null); 
 
    BundleDescription bundleDescription = this._targetPlatformAwareDelegate.getTargetPlatform(getWorkspace()) 
        .getResolvedBundle(bundleSymbolicName, osgiVersion); 
 
    if (bundleDescription == null) { 
      warn("Bundle '%s' with version '%s' not found in target platform", bundleSymbolicName, osgiVersion); 
    } 
 
    return bundleDescription; 
  } 
 
  @Override 
  protected MacroExecutionValues provideDefaultMacroExecutionValues(MacroExecutionValues values) { 
    final MacroExecutionValues defaultValues = super.provideDefaultMacroExecutionValues(values); 
 
    // Add JRE-Location to scoped properties 
    JavaRuntime javaRuntime = getJavaRuntime(); 
    defaultValues.getProperties().put("jre.location", javaRuntime.getLocation().getAbsolutePath()); 
 
    return defaultValues; 
  } 
 
  /**
   * Returns the Java Runtime for the current launch configuration 
   *  
   * @return 
   */
 
  protected JavaRuntime getJavaRuntime() { 
    LaunchConfiguration launchConfiguration = getLaunchConfiguration(); 
    JavaRuntimeRegistry javaRuntimeRegistry = ServiceRegistryAccess.instance().getService(JavaRuntimeRegistry.class); 
 
    String vmPath = launchConfiguration.getAttribute("org.eclipse.jdt.launching.JRE_CONTAINER"); 
    if (vmPath == null) { 
      return javaRuntimeRegistry.getDefaultJavaRuntime(); 
    } 
 
    JavaRuntime javaRuntime = javaRuntimeRegistry.getJavaRuntimeForPath(vmPath); 
    return javaRuntime; 
 
  } 
 
}