package org.netbeans.gradle.project.api.task;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nonnull;
import org.jtrim.utils.ExceptionHelper;
import org.netbeans.gradle.model.util.CollectionUtils;
/**
* Defines a Gradle command which might also contain
* {@link TaskVariable variable templates}. Variable templates might be added
* to task names, arguments and JVM arguments as well.
* <P>
* Instances of this class cannot be created directly but via a {@link Builder}.
* <P>
* Instances of {@code GradleCommandTemplate} are immutable and as such are safe
* to be accessed concurrently without any synchronization.
*
* @see GradleCommandExecutor
*/
public final class GradleCommandTemplate {
/**
* A builder class used to create {@link GradleCommandTemplate} instances.
* Once you have initialized all the properties, you need to call the
* {@link #create() create} method to instantiate a new
* {@code GradleCommandTemplate} instance.
* <P>
* Instances of this class may not be used concurrently but otherwise
* <I>synchronization transparent</I>, so they might be used in any context.
*/
public static final class Builder {
private final String displayName;
private final List<String> tasks;
private List<String> arguments;
private List<String> jvmArguments;
private boolean blocking;
/**
* Creates a new builder whose properties are initially set the
* appropriate properties of the specified {@code GradleCommandTemplate}.
*
* @param command the {@code GradleCommandTemplate} whose properties
* are copied to this builder. This argument cannot be {@code null}.
*
* @throws NullPointerException thrown if the specified command is
* {@code null}
*/
public Builder(@Nonnull GradleCommandTemplate command) {
this.displayName = command.getDisplayName();
this.tasks = command.getTasks();
this.arguments = command.getArguments();
this.jvmArguments = command.getJvmArguments();
this.blocking = command.isBlocking();
}
/**
* Creates a new {@code Builder} with the given task names.
* The default value for the other properties are the following:
* <ul>
* <li>{@link #getDisplayName() DisplayName}: Empty string.</li>
* <li>{@link #getArguments() Arguments}: Empty list.</li>
* <li>{@link #getJvmArguments() JvmArguments}: Empty list.</li>
* <li>{@link #isBlocking() Blocking}: {@code true}.</li>
* </ul>
*
* @param tasks the list of tasks to be executed by Gradle. This list
* cannot contain {@code null} elements nor can it be an empty list.
*
* @throws NullPointerException thrown if the specified list is
* {@code null} or contains {@code null} elements
* @throws IllegalArgumentException thrown if the specified list is
* empty
*/
@Deprecated
public Builder(@Nonnull List<String> tasks) {
this("", tasks);
}
/**
* Creates a new {@code Builder} with the given task names.
* The default value for the other properties are the following:
* <ul>
* <li>{@link #getArguments() Arguments}: Empty list.</li>
* <li>{@link #getJvmArguments() JvmArguments}: Empty list.</li>
* <li>{@link #isBlocking() Blocking}: {@code true}.</li>
* </ul>
*
* @param displayName the name of the command as displayed to the user.
* This argument cannot be {@code null} but can be an empty string
* which implies that some other sensible value is to be used
* (like the list of the tasks).
* @param tasks the list of tasks to be executed by Gradle. This list
* cannot contain {@code null} elements nor can it be an empty list.
*
* @throws NullPointerException thrown if the specified list is
* {@code null} or contains {@code null} elements or the display name
* is {@code null}.
* @throws IllegalArgumentException thrown if the specified list is
* empty
*/
public Builder(
@Nonnull String displayName,
@Nonnull List<String> tasks) {
ExceptionHelper.checkNotNullArgument(displayName, "displayName");
this.displayName = displayName;
this.tasks = CollectionUtils.copyNullSafeList(tasks);
this.arguments = Collections.emptyList();
this.jvmArguments = Collections.emptyList();
this.blocking = true;
if (this.tasks.isEmpty()) {
throw new IllegalArgumentException("Must have at least a single task specified.");
}
}
/**
* Sets the arguments specified for the Gradle command. This method call
* overwrites the values set by previous {@code setArguments} calls. The
* arguments may contain {@link TaskVariable variables to be replaced}.
* <P>
* The default value for this property if unset is an empty list.
* <P>
* Note: These arguments are specified for Gradle itself and not for the
* JVM executing Gradle. JVM arguments need to be specified via the
* {@link #setJvmArguments(List) JvmArguments} property.
*
* @param arguments the arguments to be specified for Gradle. This list
* cannot be {@code null} and cannot contain {@code null} elements
* but may be empty.
*
* @throws NullPointerException thrown if the specified list is
* {@code null} or contains {@code null} elements
*/
public void setArguments(@Nonnull List<String> arguments) {
this.arguments = CollectionUtils.copyNullSafeList(arguments);
}
/**
* Sets the arguments for the JVM running Gradle. This method call
* overwrites the values set by previous {@code setJvmArguments} calls.
* The arguments may contain {@link TaskVariable variables to be replaced}.
* <P>
* Note: Users may specify additional JVM arguments in the global
* settings and these JVM arguments will be added regardless what is
* specified in this list.
* <P>
* <B>Warning</B>: Specifying different JVM arguments for different
* commands are likely to spawn a new Gradle daemon. Note that the
* Gradle daemon is a long lived process and by default has a
* considerable memory footprint. Therefore, spawning new Gradle daemons
* should be avoided if possible.
*
* @param jvmArguments the arguments for the JVM running Gradle. This
* list cannot be {@code null} and cannot contain {@code null}
* elements but may be empty.
*
* @throws NullPointerException thrown if the specified list is
* {@code null} or contains {@code null} elements
*/
public void setJvmArguments(@Nonnull List<String> jvmArguments) {
this.jvmArguments = CollectionUtils.copyNullSafeList(jvmArguments);
}
/**
* Sets if this Gradle command might block other commands indefinitely
* or not. This method call overwrites the values set by previous
* {@code setBlocking} calls.
* <P>
* Gradle commands will be executed so that if a task is not blocking
* (this method returns {@code false}), then all subsequent tasks will
* wait for the non-blocking task to complete. The reason for this
* distinction is to prevent accidentally starting multiple Gradle
* daemons if multiple Gradle commands are scheduled concurrently.
* <P>
* An example for a blocking task is "debug" and "build" should usually
* be considered as a non-blocking task.
*
* @param blocking {@code true} if this Gradle command might block other
* commands indefinitely, {@code false} otherwise
*/
public void setBlocking(boolean blocking) {
this.blocking = blocking;
}
/**
* Creates a new {@code GradleCommandTemplate} with the currently
* specified properties for this builder. Subsequent adjustment to this
* builder will have no effect on the returned instance.
*
* @return a new {@code GradleCommandTemplate} with the currently
* specified properties for this builder. This method never returns
* {@code null}.
*/
@Nonnull
public GradleCommandTemplate create() {
return new GradleCommandTemplate(this);
}
}
private final String displayName;
private final List<String> tasks;
private final List<String> arguments;
private final List<String> jvmArguments;
private final boolean blocking;
private GradleCommandTemplate(Builder builder) {
this.displayName = builder.displayName;
this.tasks = builder.tasks;
this.arguments = builder.arguments;
this.jvmArguments = builder.jvmArguments;
this.blocking = builder.blocking;
}
/**
* Returns the display name of the command to be executed. This display name
* can be used in progress text and output window captions.
* <P>
* In case this method returns an empty a string a sensible default value
* is to be used.
*
* @return the display name of the command to be executed. This method
* never returns {@code null}.
*
* @see #getSafeDisplayName()
*/
@Nonnull
public String getDisplayName() {
return displayName;
}
/**
* Returns the display name of the command to be executed or a sensible
* default when the display name is an empty string. This display name
* can be used in progress text and output window captions.
* <P>
* In case this method returns an empty a string a sensible default value
* is to be used.
*
* @return the display name of the command to be executed. This method
* never returns {@code null}.
*/
@Nonnull
public String getSafeDisplayName() {
return displayName.isEmpty() ? tasks.toString() : displayName;
}
/**
* Returns the list of tasks to be executed by Gradle. Tasks will be
* executed in the order they were specified if possible without
* violating task dependencies. The task names may contain
* {@link TaskVariable variables to be replaced}.
*
* @return the list of tasks to be executed by Gradle. This method never
* returns {@code null}, the returned list does not contain
* {@code null} elements and is never empty.
*/
@Nonnull
public List<String> getTasks() {
return tasks;
}
/**
* Returns the arguments for this Gradle command.
* <P>
* Note: These arguments are specified for Gradle itself and not for the
* JVM executing Gradle. JVM arguments need to be specified via the
* {@link #getJvmArguments() JvmArguments} property.
*
* @return the arguments for this Gradle command. This method
* never returns {@code null} and the returned list does not contain
* {@code null} elements but may be empty.
*/
@Nonnull
public List<String> getArguments() {
return arguments;
}
/**
* Returns the JVM arguments for this Gradle command.
* These arguments are used to start the JVM process executing Gradle
* which is executing the Gradle command.
* <P>
* Note: Users may specify additional JVM arguments in the global
* settings and these JVM arguments will be added regardless what is
* specified in this list.
* <P>
* <B>Warning</B>: Specifying different JVM arguments for different
* commands are likely to spawn a new Gradle daemon. Note that the
* Gradle daemon is a long lived process and by default has a
* considerable memory footprint. Therefore, spawning new Gradle daemons
* should be avoided if possible.
*
* @return the last set JVM arguments for this Gradle command. This
* method never returns {@code null} and the returned list does not
* contain {@code null} elements but may be empty.
*/
@Nonnull
public List<String> getJvmArguments() {
return jvmArguments;
}
/**
* Returns {@code true} if this Gradle command might block other
* commands indefinitely.
* <P>
* Gradle commands will be executed so that if a task is not blocking
* (this method returns {@code false}), then all subsequent tasks will
* wait for the non-blocking task to complete. The reason for this
* distinction is to prevent accidentally starting multiple Gradle
* daemons if multiple Gradle commands are scheduled concurrently.
* <P>
* An example for a blocking task is "debug". An example for a non-blocking
* task is "build".
*
* @return {@code true} if this Gradle command might block other
* commands indefinitely, {@code false} otherwise
*/
public boolean isBlocking() {
return blocking;
}
}