private void printUsedBaselines(ClearCaseLogger logger, List<Baseline> latestBls) {
    for (Baseline bl : latestBls) {
      String blString;

      if (bl.isCreated()) {
        blString = "* baseline: %s (created on component %s)";
      } else {
        blString = "  baseline: %s (component %s unmodified)";
      }

      logger.log(String.format(blString, bl.toString(), bl.getComponent().toString()));
    }
  }
  /** {@inheritDoc} * */
  @Override
  public boolean perform(AbstractBuild<?, ?> build, Launcher l, BuildListener listener)
      throws InterruptedException, IOException {

    if (build.getProject().getScm() instanceof ClearCaseUcmSCM) {
      try {
        File ctLogFile = ClearToolLogFile.getCleartoolLogFile(build);
        ClearCaseLogger logger = new ClearCaseLogger(listener, ctLogFile);
        logger.log("### Begin Baseline creation/promotion ###");
        boolean buildOK =
            build.getResult().equals(Result.SUCCESS) || build.getResult().equals(Result.UNSTABLE);

        if (!buildOK && this.skipOnBuildFailure) {
          logger.log(
              "Build result is "
                  + build.getResult()
                  + ". "
                  + "Skipping the baseline creation/promotion step.");
          return false;
        }

        ///// init variables //////////////////////////////////////////////////////////////
        ClearCaseUcmSCM scm = (ClearCaseUcmSCM) build.getProject().getScm();
        EnvVars env = build.getEnvironment(listener);
        String nodeName = Computer.currentComputer().getName();
        ClearCaseConfiguration ccConfig = scm.fetchClearCaseConfig(nodeName);
        FilePath workspace;
        StringParameterValue wsParam =
            CCParametersAction.getBuildParameter(build, ORIGINAL_WORKSPACE_ENVSTR);
        if (wsParam != null) {
          workspace = new FilePath(build.getWorkspace().getChannel(), wsParam.value);
        } else {
          workspace = build.getWorkspace();
        }
        ClearTool ct =
            scm.createClearTool(
                ccConfig.getCleartoolExe(),
                workspace,
                build.getBuiltOn().getRootPath(),
                env,
                ctLogFile,
                null);

        View view = ClearCaseUcmSCM.getBuildView(build);

        Stream stream = view.getStream();

        ///// check stream lock state /////////////////////////////////////////////////////
        LockState state = ct.getStreamLockState(stream);
        stream.setLockState(state);
        switch (state) {
          case NONE:
          case UNLOCKED:
            break;
          default:
            logger.log(
                "WARNING: building on a '" + state + "' stream. No baseline will be created.");
            return false;
        }

        ///// resolve variables in baseline name //////////////////////////////////////////
        String baseName = env.expand(this.namePattern);
        String comment = env.expand(this.commentPattern);

        /* illegal characters removal */
        baseName = baseName.replaceAll("[\\s\\\\\\/:\\?\\*\\|]+", "_");
        Pattern p = Pattern.compile("(\\$\\{.+?\\})");
        Matcher match = p.matcher(baseName);
        if (match.find()) {
          throw new ClearToolError(
              String.format(
                  "Illegal characters found "
                      + "in baseline name : %s. "
                      + "An environment variable may not have been resolved.",
                  match.group()));
        }

        ///// main process ////////////////////////////////////////////////////////////////
        logger.log("Retrieving components details...");
        List<Component> components = resolveComponents(stream, ct);

        logger.log("Creating new baselines...");
        List<Baseline> createdBls = createBaselines(baseName, comment, ct, view, components);

        logger.log("Retrieving latest baselines...");
        /* retrieval of the full names of the baselines */
        List<Baseline> latestBls = ct.getLatestBaselines(stream);

        /* get every component attached to the latest baselines */
        matchComponentsToBaselines(ct, stream, latestBls);
        /* resolve created baselines */
        markCreatedBaselines(createdBls, latestBls);

        printUsedBaselines(logger, latestBls);

        if (createdBls.isEmpty()) {
          logger.log("No baseline was created.");
        } else {
          /* get vob dependent promotion levels */
          ct.fetchPromotionLevels(stream.getPvob());

          if (buildOK) {
            logger.log("Promoting created baselines...");

            /* On success, promote all the baselines that hudson created to "BUILT" */
            for (Baseline bl : createdBls) {
              ct.changeBaselinePromotionLevel(bl, PromotionLevel.BUILT);
              logger.log(printPromotedBl(bl, ct.print(PromotionLevel.BUILT)));
            }

            /* recommend all baselines that meet the stream's promotion level requirements */
            if (this.recommend) {
              logger.log("Recommending created baselines...");
              ct.recommendAllEligibleBaselines(stream);
            }
            /* Rebase a dynamic view */
            if (this.rebaseDynamicView) {
              logger.log(
                  String.format("Rebasing view: %s with created baselines...", dynamicViewName));

              View dynView = new View(dynamicViewName, stream, true);
              ct.rebaseDynamicView(dynView, createdBls);
            }
          } else {
            /* On failure, demote all the baselines that hudson created to "REJECTED" */
            logger.log("Rejecting created baselines...");
            for (Baseline bl : createdBls) {
              ct.changeBaselinePromotionLevel(bl, PromotionLevel.REJECTED);
              logger.log(printPromotedBl(bl, ct.print(PromotionLevel.REJECTED)));
            }
          }
        }

        publishBaselinesAsParams(build, latestBls);

        logger.log("~~~ End Baseline creation/promotion ~~~");

      } catch (ClearToolError ctError) {
        listener.getLogger().println(ctError.toString());
        build.setResult(Result.FAILURE);
        return false;
      } catch (Exception e) {
        e.printStackTrace(listener.getLogger());
        build.setResult(Result.FAILURE);
        return false;
      }
    } else {
      listener.getLogger().println("ERROR: Baselines are only handled by Clearcase UCM.");
      return false;
    }
    return true;
  } // perform()