LifecycleExecutor.java
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.api.services;
import java.util.List;
import java.util.function.Predicate;
import org.apache.maven.api.LifecyclePlan;
import org.apache.maven.api.MojoExecution;
import org.apache.maven.api.Project;
import org.apache.maven.api.Service;
import org.apache.maven.api.Session;
import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.annotations.Nonnull;
/**
* Service for calculating and executing Maven lifecycle plans for a single project.
*
* <p>This service separates lifecycle <em>planning</em> from <em>execution</em>, enabling
* callers to inspect and filter the plan before deciding what to execute. This is the
* primary entry point for IDE embedders and tools that need programmatic lifecycle control.
*
* <h2>Core workflow</h2>
* The service exposes two abstract operations:
* <ol>
* <li>{@link #plan(LifecyclePlanRequest)} ��� calculates an immutable {@link LifecyclePlan}
* containing the configured mojo executions for the requested phases/goals</li>
* <li>{@link #execute(LifecycleExecutionRequest)} ��� runs all or a filtered subset of a
* previously calculated plan</li>
* </ol>
*
* <p>Convenience defaults ({@link #plan(Session, Project, java.util.List)},
* {@link #execute(Session, LifecyclePlan)}, {@link #planAndExecute(Session, Project, java.util.List)})
* and {@link Session} shortcuts ({@link Session#planLifecycle(Project, java.util.List)},
* {@link Session#executeLifecycle(LifecyclePlan)}) cover the common cases without
* constructing request objects directly.
*
* <h2>Example</h2>
* <pre>{@code
* // Plan the "resources" phase for a project
* LifecyclePlanResult planResult = session.planLifecycle(project, "resources");
* LifecyclePlan plan = planResult.plan();
*
* // Inspect what would run
* for (MojoExecution mojo : plan.executions()) {
* System.out.println(mojo.lifecyclePhase().orElse("") + " : " + mojo.goal());
* }
*
* // Execute the full plan
* LifecycleExecutionResult result = session.executeLifecycle(plan);
*
* // Or execute only specific mojos (e.g. skip resource copying)
* result = session.executeLifecycle(plan,
* mojo -> !mojo.goal().equals("resources"));
* }</pre>
*
* <h2>Scope and limitations</h2>
* <ul>
* <li>This service operates on a <strong>single project</strong>. Reactor-level
* (multi-project) orchestration is handled by a separate mechanism.</li>
* <li>The plan uses the same graph-based calculation as the concurrent build
* infrastructure, but plugin resolution happens eagerly during {@code plan()},
* which requires that all plugin artifacts are already resolvable.</li>
* <li>On execution failure, the thrown {@link LifecycleExecutorException} carries
* a {@linkplain LifecycleExecutorException#result() partial result} with per-mojo
* success/failure status.</li>
* </ul>
*
* <p>This is the Maven 4 API lifecycle executor. The legacy
* {@code org.apache.maven.lifecycle.LifecycleExecutor} in the compatibility layer
* serves a different role (full reactor execution).
*
* @since 4.2.0
* @see LifecyclePlan
* @see Session#planLifecycle(Project, java.util.List)
* @see Session#executeLifecycle(LifecyclePlan)
*/
@Experimental
public interface LifecycleExecutor extends Service {
/**
* Calculates a lifecycle plan without executing it.
*
* @param request the planning request
* @return the planning result
* @throws LifecycleExecutorException if the lifecycle plan cannot be calculated
*/
@Nonnull
LifecyclePlanResult plan(@Nonnull LifecyclePlanRequest request);
/**
* Executes all or part of a previously calculated lifecycle plan.
*
* @param request the execution request
* @return the execution result
* @throws LifecycleExecutorException if lifecycle execution fails
* @throws IllegalArgumentException if the plan was not produced by this service
*/
@Nonnull
LifecycleExecutionResult execute(@Nonnull LifecycleExecutionRequest request);
/**
* Calculates a lifecycle plan without executing it.
*
* @param session the current session
* @param project the project for which to calculate the plan
* @param tasks lifecycle phases or plugin goals used to calculate the plan
* @return the lifecycle planning result
* @throws LifecycleExecutorException if the lifecycle plan cannot be calculated
* @see #plan(LifecyclePlanRequest)
*/
@Nonnull
default LifecyclePlanResult plan(@Nonnull Session session, @Nonnull Project project, @Nonnull List<String> tasks) {
return plan(LifecyclePlanRequest.build(session, project, tasks));
}
/**
* Executes a previously calculated lifecycle plan.
*
* @param session the current session
* @param plan the lifecycle plan to execute
* @return the lifecycle execution result
* @throws LifecycleExecutorException if lifecycle execution fails
* @throws IllegalArgumentException if the plan was not produced by this service
* @see #execute(LifecycleExecutionRequest)
*/
@Nonnull
default LifecycleExecutionResult execute(@Nonnull Session session, @Nonnull LifecyclePlan plan) {
return execute(LifecycleExecutionRequest.build(session, plan));
}
/**
* Executes the entries of a previously calculated lifecycle plan that are accepted by the supplied filter.
*
* @param session the current session
* @param plan the lifecycle plan to execute
* @param filter predicate deciding which configured mojo executions are executed
* @return the lifecycle execution result
* @throws LifecycleExecutorException if lifecycle execution fails
* @throws IllegalArgumentException if the plan was not produced by this service
* @see #execute(LifecycleExecutionRequest)
*/
@Nonnull
default LifecycleExecutionResult execute(
@Nonnull Session session, @Nonnull LifecyclePlan plan, @Nonnull Predicate<MojoExecution> filter) {
return execute(LifecycleExecutionRequest.build(session, plan, filter));
}
/**
* Calculates and executes a lifecycle plan.
*
* @param session the current session
* @param project the project for which to execute the lifecycle
* @param tasks lifecycle phases or plugin goals used to calculate the plan
* @return the lifecycle execution result
* @throws LifecycleExecutorException if the lifecycle plan cannot be calculated or executed
* @throws IllegalArgumentException if the calculated plan cannot be executed by this service
* @see #plan(LifecyclePlanRequest)
* @see #execute(LifecycleExecutionRequest)
*/
@Nonnull
default LifecycleExecutionResult planAndExecute(
@Nonnull Session session, @Nonnull Project project, @Nonnull List<String> tasks) {
return execute(session, plan(session, project, tasks).plan());
}
/**
* Calculates a lifecycle plan and executes the entries accepted by the supplied filter.
*
* @param session the current session
* @param project the project for which to execute the lifecycle
* @param tasks lifecycle phases or plugin goals used to calculate the plan
* @param filter predicate deciding which configured mojo executions are executed
* @return the lifecycle execution result
* @throws LifecycleExecutorException if the lifecycle plan cannot be calculated or executed
* @throws IllegalArgumentException if the calculated plan cannot be executed by this service
* @see #plan(LifecyclePlanRequest)
* @see #execute(LifecycleExecutionRequest)
*/
@Nonnull
default LifecycleExecutionResult planAndExecute(
@Nonnull Session session,
@Nonnull Project project,
@Nonnull List<String> tasks,
@Nonnull Predicate<MojoExecution> filter) {
return execute(session, plan(session, project, tasks).plan(), filter);
}
}