All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.gradle.internal.Actions Maven / Gradle / Ivy

There is a newer version: 8.6
Show newest version
/*
 * Copyright 2012 the original author or authors.
 *
 * Licensed 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.gradle.internal;

import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import org.gradle.api.Action;
import org.gradle.api.Transformer;
import org.gradle.api.specs.Spec;

import javax.annotation.Nullable;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;

public abstract class Actions {

    static final Action DO_NOTHING = new NullAction();
    private static final Predicate> DOES_SOMETHING = new Predicate>() {
        @Override
        public boolean apply(@Nullable Action input) {
            return input != DO_NOTHING;
        }
    };

    /**
     * Creates an action implementation that simply does nothing.
     *
     * A new action instance is created each time.
     *
     * @return An action object with an empty implementation
     */
    @SuppressWarnings("unchecked")
    public static  Action doNothing() {
        return (Action) DO_NOTHING;
    }

    private static class NullAction implements Action, Serializable {
        public void execute(T t) {
        }
    }

    /**
     * Creates an action that will call each of the given actions in order.
     *
     * @param actions The actions to make a composite of.
     * @param  The type of the object that action is for
     * @return The composite action.
     */
    public static  Action composite(Iterable> actions) {
        return composite(ImmutableList.copyOf(Iterables.filter(actions, DOES_SOMETHING)));
    }

    /**
     * Creates an action that will call each of the given actions in order.
     *
     * @param actions The actions to make a composite of.
     * @param  The type of the object that action is for
     * @return The composite action.
     */
    public static  Action composite(List> actions) {
        if (actions.isEmpty()) {
            return doNothing();
        }
        if (actions.size() == 1) {
            return Cast.uncheckedCast(actions.get(0));
        }
        return new CompositeAction(actions);
    }

    /**
     * Creates an action that will call each of the given actions in order.
     *
     * @param actions The actions to make a composite of.
     * @param  The type of the object that action is for
     * @return The composite action.
     */
    @SafeVarargs
    public static  Action composite(Action... actions) {
        List> filtered = Lists.newArrayListWithCapacity(actions.length);
        for (Action action : actions) {
            if (DOES_SOMETHING.apply(action)) {
                filtered.add(action);
            }
        }
        return composite(filtered);
    }

    private static class CompositeAction implements Action {
        private final List> actions;

        private CompositeAction(List> actions) {
            this.actions = actions;
        }

        public void execute(T item) {
            for (Action action : actions) {
                action.execute(item);
            }
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }

            CompositeAction that = (CompositeAction) o;

            if (!actions.equals(that.actions)) {
                return false;
            }

            return true;
        }

        @Override
        public int hashCode() {
            return actions.hashCode();
        }
    }

    /**
     * Creates a new composite action, where the argument is first transformed.
     *
     * @param action The action.
     * @param transformer The transformer to transform the argument with
     * @param  The type the action is expecting (that the argument is transformed to)
     * @param  The type of the original argument
     * @return An action that transforms an object of type I to type O to give to the given action
     */
    public static  Action transformBefore(final Action action, final Transformer transformer) {
        return new TransformingActionAdapter(transformer, action);
    }

    private static class TransformingActionAdapter implements Action {
        private final Transformer transformer;
        private final Action action;

        private TransformingActionAdapter(Transformer transformer, Action action) {
            this.transformer = transformer;
            this.action = action;
        }

        public void execute(I thing) {
            T transformed = transformer.transform(thing);
            action.execute(transformed);
        }
    }

    /**
     * Adapts an action to a different type by casting the object before giving it to the action.
     *
     * @param actionType The type the action is expecting
     * @param action The action
     * @param  The type the action is expecting
     * @param  The type before casting
     * @return An action that casts the object to the given type before giving it to the given action
     */
    public static  Action castBefore(final Class actionType, final Action action) {
        return transformBefore(action, Transformers.cast(actionType));
    }

    /**
     * Wraps the given runnable in an {@link Action}, where the execute implementation runs the runnable ignoring the argument.
     *
     * If the given runnable is {@code null}, the action returned is effectively a noop.
     *
     * @param runnable The runnable to run for the action execution.
     * @return An action that runs the given runnable, ignoring the argument.
     */
    public static  Action toAction(@Nullable Runnable runnable) {
        //TODO SF this method accepts Closure instance as parameter but does not work correctly for it
        if (runnable == null) {
            return Actions.doNothing();
        } else {
            return new RunnableActionAdapter(runnable);
        }
    }

    private static class RunnableActionAdapter implements Action {
        private final Runnable runnable;

        private RunnableActionAdapter(Runnable runnable) {
            this.runnable = runnable;
        }

        public void execute(T t) {
            runnable.run();
        }

        @Override
        public String toString() {
            return "RunnableActionAdapter{runnable=" + runnable + "}";
        }
    }

    /**
     * Creates a new action that only forwards arguments on to the given filter if they are satisfied by the given spec.
     *
     * @param action The action to delegate filtered items to
     * @param filter The spec to use to filter items by
     * @param  The type of item the action expects
     * @return A new action that only forwards arguments on to the given filter is they are satisfied by the given spec.
     */
    public static  Action filter(Action action, Spec filter) {
        return new FilteredAction(action, filter);
    }

    private static class FilteredAction implements Action {
        private final Spec filter;
        private final Action action;

        public FilteredAction(Action action, Spec filter) {
            this.filter = filter;
            this.action = action;
        }

        public void execute(T t) {
            if (filter.isSatisfiedBy(t)) {
                action.execute(t);
            }
        }
    }

    public static  T with(T instance, Action action) {
        action.execute(instance);
        return instance;
    }

    public static  Action add(final Collection collection) {
        return new Action() {
            @Override
            public void execute(T t) {
                collection.add(t);
            }
        };
    }

    public static  Action set(Action... actions) {
        return ImmutableActionSet.of(actions);
    }
}