/**
   * Generates an executable plan.
   *
   * @param planName the plan name
   * @param alternative the alternative to base the workflow on
   * @param measures the measures to include in the workflow
   * @param sourceMimetype the source mimetype of the workflow
   * @param targetMimetype the target mimetype of the workflow
   * @return an executable plan
   * @throws PlanningException if an error occurred during generation
   */
  @Asynchronous
  public Future<DigitalObject> generateExecutablePlan(
      final String planName,
      final Alternative alternative,
      final List<String> measures,
      final String sourceMimetype,
      final String targetMimetype)
      throws PlanningException {
    DigitalObject workflow = new DigitalObject();

    String name = planName + " - " + alternative.getName();
    T2FlowExecutablePlanGenerator generator =
        new T2FlowExecutablePlanGenerator(name, user.getFullName());

    // Add ports
    generator.addSourcePort();
    generator.addTargetPort();

    // Migration action
    PreservationActionDefinition action = alternative.getAction();
    if (action != null) {
      try {
        WorkflowDescription wf = MyExperimentRESTClient.getWorkflow(action.getDescriptor());
        if (wf != null) {
          HashMap<String, String> parameters = new HashMap<String, String>();
          for (Parameter p : action.getParams()) {
            parameters.put(p.getName(), p.getValue());
          }
          wf.readMetadata();
          String workflowContent = MyExperimentRESTClient.getWorkflowContent(wf);
          generator.setMigrationComponent(wf, workflowContent, parameters);
        } else {
          log.warn(String.format("The workflow [%s] could not be found.", action.getDescriptor()));
        }
      } catch (Exception e) {
        throw new PlanningException(
            "An error occured querying myExperiment migration component", e);
      }
    }

    // Add QA components
    addQaComponents(generator, measures, sourceMimetype, targetMimetype);

    // Create digital object
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    OutputStreamWriter writer = new OutputStreamWriter(out);

    try {
      generator.generate(writer);
    } catch (IOException e) {
      log.warn("An error occured generating the executable plan.", e.getMessage());
      throw new PlanningException("An error occured generating the executable plan.", e);
    } finally {
      if (writer != null) {
        try {
          writer.close();
        } catch (IOException e) {
          log.warn(
              "An error occured closing the executable plan generator writer.", e.getMessage());
          throw new PlanningException(
              "An error occured closing the executable plan generator writer.", e);
        }
      }
    }

    byte[] data = out.toByteArray();
    ByteStream bsData = new ByteStream();
    bsData.setData(data);

    workflow.setContentType("application/vnd.taverna.t2flow+xml");
    workflow.setData(bsData);
    workflow.setFullname(FileUtils.makeFilename(name + ".t2flow"));

    return new AsyncResult<DigitalObject>(workflow);
  }