@Override
  public Mono<Void> stop(StopApplicationRequest request) {
    return ValidationUtils.validate(request)
        .map(
            new Function<StopApplicationRequest, String>() {

              @Override
              public String apply(StopApplicationRequest request) {
                return request.getName();
              }
            })
        .and(this.spaceId)
        .then(
            function(
                new Function2<String, String, Mono<String>>() {

                  @Override
                  public Mono<String> apply(String application, String spaceId) {
                    return getApplicationIdWhere(
                        DefaultApplications.this.cloudFoundryClient,
                        application,
                        spaceId,
                        not(isIn(STOPPED_STATE)));
                  }
                }))
        .then(
            new Function<String, Mono<AbstractApplicationResource>>() {

              @Override
              public Mono<AbstractApplicationResource> apply(String applicationId) {
                return stopApplication(DefaultApplications.this.cloudFoundryClient, applicationId);
              }
            })
        .after();
  }
  @Override
  public Mono<Void> rename(RenameApplicationRequest request) {
    return Mono.when(ValidationUtils.validate(request), this.spaceId)
        .then(
            function(
                new Function2<
                    RenameApplicationRequest,
                    String,
                    Mono<Tuple2<String, RenameApplicationRequest>>>() {

                  @Override
                  public Mono<Tuple2<String, RenameApplicationRequest>> apply(
                      RenameApplicationRequest request, String spaceId) {
                    return getApplicationId(
                            DefaultApplications.this.cloudFoundryClient, request.getName(), spaceId)
                        .and(Mono.just(request));
                  }
                }))
        .then(
            function(
                new Function2<String, RenameApplicationRequest, Mono<UpdateApplicationResponse>>() {

                  @Override
                  public Mono<UpdateApplicationResponse> apply(
                      String applicationId, RenameApplicationRequest request) {
                    return requestUpdateApplicationRename(
                        DefaultApplications.this.cloudFoundryClient,
                        applicationId,
                        request.getNewName());
                  }
                }))
        .after();
  }
  @Override
  public Mono<ApplicationDetail> get(GetApplicationRequest request) {
    return ValidationUtils.validate(request)
        .and(this.spaceId)
        .then(
            function(
                new Function2<GetApplicationRequest, String, Mono<AbstractApplicationResource>>() {

                  @Override
                  public Mono<AbstractApplicationResource> apply(
                      GetApplicationRequest request, String spaceId) {
                    return getApplication(
                        DefaultApplications.this.cloudFoundryClient, request.getName(), spaceId);
                  }
                }))
        .then(
            new Function<
                AbstractApplicationResource,
                Mono<
                    Tuple4<
                        ApplicationStatisticsResponse,
                        SummaryApplicationResponse,
                        GetStackResponse,
                        ApplicationInstancesResponse>>>() {

              @Override
              public Mono<
                      Tuple4<
                          ApplicationStatisticsResponse,
                          SummaryApplicationResponse,
                          GetStackResponse,
                          ApplicationInstancesResponse>>
                  apply(AbstractApplicationResource applicationResource) {
                return getAuxiliaryContent(
                    DefaultApplications.this.cloudFoundryClient, applicationResource);
              }
            })
        .map(
            function(
                new Function4<
                    ApplicationStatisticsResponse,
                    SummaryApplicationResponse,
                    GetStackResponse,
                    ApplicationInstancesResponse,
                    ApplicationDetail>() {

                  @Override
                  public ApplicationDetail apply(
                      ApplicationStatisticsResponse applicationStatisticsResponse,
                      SummaryApplicationResponse summaryApplicationResponse,
                      GetStackResponse getStackResponse,
                      ApplicationInstancesResponse applicationInstancesResponse) {
                    return toApplicationDetail(
                        applicationStatisticsResponse,
                        summaryApplicationResponse,
                        getStackResponse,
                        applicationInstancesResponse);
                  }
                }));
  }
  @Override
  public Mono<Void> delete(DeleteApplicationRequest request) {
    return ValidationUtils.validate(request)
        .and(this.spaceId)
        .then(
            function(
                new Function2<
                    DeleteApplicationRequest,
                    String,
                    Mono<Tuple2<Optional<List<Route>>, String>>>() {

                  @Override
                  public Mono<Tuple2<Optional<List<Route>>, String>> apply(
                      DeleteApplicationRequest request, String spaceId) {
                    return getRoutesAndApplicationId(
                        DefaultApplications.this.cloudFoundryClient, request, spaceId);
                  }
                }))
        .then(
            function(
                new Function2<Optional<List<Route>>, String, Mono<String>>() {

                  @Override
                  public Mono<String> apply(
                      Optional<List<Route>> routes, final String applicationId) {
                    return deleteRoutes(DefaultApplications.this.cloudFoundryClient, routes)
                        .after(
                            new Supplier<Mono<String>>() {

                              @Override
                              public Mono<String> get() {
                                return Mono.just(applicationId);
                              }
                            });
                  }
                }))
        .then(
            new Function<String, Mono<Void>>() {

              @Override
              public Mono<Void> apply(String applicationId) {
                return requestDeleteApplication(
                    DefaultApplications.this.cloudFoundryClient, applicationId);
              }
            });
  }
  @Override
  public Mono<Void> restart(RestartApplicationRequest request) {
    return Mono.when(ValidationUtils.validate(request), this.spaceId)
        .then(
            function(
                new Function2<
                    RestartApplicationRequest, String, Mono<AbstractApplicationResource>>() {
                  @Override
                  public Mono<AbstractApplicationResource> apply(
                      RestartApplicationRequest request, String spaceId) {
                    return getApplication(cloudFoundryClient, request.getName(), spaceId);
                  }
                }))
        .then(
            new Function<AbstractApplicationResource, Mono<AbstractApplicationResource>>() {
              @Override
              public Mono<AbstractApplicationResource> apply(
                  final AbstractApplicationResource resource) {
                return Mono.just(resource)
                    .as(
                        ifThen(
                            not(isIn(STOPPED_STATE)),
                            new Function<
                                AbstractApplicationResource, Mono<AbstractApplicationResource>>() {
                              @Override
                              public Mono<AbstractApplicationResource> apply(
                                  AbstractApplicationResource resource) {
                                return stopApplication(
                                    cloudFoundryClient, ResourceUtils.getId(resource));
                              }
                            }))
                    .then(
                        new Function<
                            AbstractApplicationResource, Mono<AbstractApplicationResource>>() {

                          @Override
                          public Mono<AbstractApplicationResource> apply(
                              AbstractApplicationResource resource) {
                            return startApplication(
                                cloudFoundryClient, ResourceUtils.getId(resource));
                          }
                        });
              }
            })
        .after();
  }
  @Override
  public Mono<Void> scale(final ScaleApplicationRequest request) {
    return Mono.when(ValidationUtils.validate(request), this.spaceId)
        .where(
            predicate(
                new Predicate2<ScaleApplicationRequest, String>() {

                  @Override
                  public boolean test(ScaleApplicationRequest request, String spaceId) {
                    return areModifiersPresent(request);
                  }
                }))
        .then(
            function(
                new Function2<
                    ScaleApplicationRequest,
                    String,
                    Mono<Tuple2<ScaleApplicationRequest, String>>>() {

                  @Override
                  public Mono<Tuple2<ScaleApplicationRequest, String>> apply(
                      ScaleApplicationRequest request, String spaceId) {
                    return Mono.when(
                        Mono.just(request),
                        getApplicationId(cloudFoundryClient, request.getName(), spaceId));
                  }
                }))
        .then(
            function(
                new Function2<
                    ScaleApplicationRequest,
                    String,
                    Mono<Tuple2<ScaleApplicationRequest, AbstractApplicationResource>>>() {

                  @Override
                  public Mono<Tuple2<ScaleApplicationRequest, AbstractApplicationResource>> apply(
                      ScaleApplicationRequest request, String applicationId) {
                    return Mono.when(
                        Mono.just(request),
                        requestUpdateApplicationScale(
                            cloudFoundryClient,
                            applicationId,
                            request.getDiskLimit(),
                            request.getInstances(),
                            request.getMemoryLimit()));
                  }
                }))
        .where(
            predicate(
                new Predicate2<ScaleApplicationRequest, AbstractApplicationResource>() {

                  @Override
                  public boolean test(
                      ScaleApplicationRequest request, AbstractApplicationResource resource) {
                    return isRestartRequired(request, resource);
                  }
                }))
        .then(
            function(
                new Function2<
                    ScaleApplicationRequest,
                    AbstractApplicationResource,
                    Mono<AbstractApplicationResource>>() {

                  @Override
                  public Mono<AbstractApplicationResource> apply(
                      ScaleApplicationRequest request, AbstractApplicationResource resource) {
                    return restartApplication(cloudFoundryClient, resource);
                  }
                }))
        .after();
  }