
org.gradle.language.internal.DefaultBinaryCollection Maven / Gradle / Ivy
/*
* Copyright 2017 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.language.internal;
import com.google.common.collect.ImmutableSet;
import groovy.lang.Closure;
import org.gradle.api.Action;
import org.gradle.api.component.SoftwareComponent;
import org.gradle.api.internal.provider.AbstractReadOnlyProvider;
import org.gradle.api.provider.ProviderFactory;
import org.gradle.api.specs.Spec;
import org.gradle.internal.ImmutableActionSet;
import org.gradle.language.BinaryCollection;
import org.gradle.language.BinaryProvider;
import org.gradle.util.ConfigureUtil;
import javax.annotation.Nullable;
import javax.inject.Inject;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
// TODO - error messages
// TODO - display names for this container and the Provider implementations
public class DefaultBinaryCollection implements BinaryCollection {
private enum State {
Collecting, Realizing, Finalized
}
private final Class elementType;
private final ProviderFactory providerFactory;
private final Set elements = new LinkedHashSet();
private List> pending = new LinkedList>();
private State state = State.Collecting;
private ImmutableActionSet knownActions = ImmutableActionSet.empty();
private ImmutableActionSet configureActions = ImmutableActionSet.empty();
private ImmutableActionSet finalizeActions = ImmutableActionSet.empty();
@Inject
public DefaultBinaryCollection(Class elementType, ProviderFactory providerFactory) {
this.elementType = elementType;
this.providerFactory = providerFactory;
}
@Override
public BinaryProvider get(final Class type, final Spec super S> spec) {
SingleElementProvider provider = new SingleElementProvider(type, spec);
if (state == State.Collecting) {
pending.add(provider);
} else {
provider.selectNow();
}
return provider;
}
@Override
public BinaryProvider getByName(final String name) {
return get(elementType, new Spec() {
@Override
public boolean isSatisfiedBy(T element) {
return element.getName().equals(name);
}
});
}
@Override
public BinaryProvider get(Spec super T> spec) {
return get(elementType, spec);
}
@Override
public void whenElementKnown(Action super T> action) {
if (state != State.Collecting) {
throw new IllegalStateException("Cannot add actions to this collection as it has already been realized.");
}
knownActions = knownActions.add(action);
}
@Override
public void whenElementKnown(final Class type, final Action super S> action) {
whenElementKnown(new TypeFilteringAction(type, action));
}
@Override
public void whenElementFinalized(Action super T> action) {
if (state == State.Finalized) {
for (T element : elements) {
action.execute(element);
}
} else {
finalizeActions = finalizeActions.add(action);
}
}
@Override
public void whenElementFinalized(Class type, Action super S> action) {
whenElementFinalized(new TypeFilteringAction(type, action));
}
@Override
public void configureEach(Action super T> action) {
if (state != State.Collecting) {
throw new IllegalStateException("Cannot add actions to this collection as it has already been realized.");
}
configureActions = configureActions.add(action);
}
@Override
public void configureEach(Class type, Action super S> action) {
configureEach(new TypeFilteringAction(type, action));
}
public void add(T element) {
if (state != State.Collecting) {
throw new IllegalStateException("Cannot add an element to this collection as it has already been realized.");
}
elements.add(element);
}
/**
* Realizes the contents of this collection, running configuration actions and firing notifications. No further elements can be added.
*/
public void realizeNow() {
if (state != State.Collecting) {
throw new IllegalStateException("Cannot realize this collection as it has already been realized.");
}
state = State.Realizing;
for (T element : elements) {
knownActions.execute(element);
}
knownActions = ImmutableActionSet.empty();
for (SingleElementProvider> provider : pending) {
provider.selectNow();
}
pending = null;
for (T element : elements) {
configureActions.execute(element);
}
configureActions = ImmutableActionSet.empty();
state = State.Finalized;
for (T element : elements) {
finalizeActions.execute(element);
}
finalizeActions = ImmutableActionSet.empty();
}
@Override
public Set get() {
if (state != State.Finalized) {
throw new IllegalStateException("Cannot query the elements of this container as the elements have not been created yet.");
}
return ImmutableSet.copyOf(elements);
}
private class SingleElementProvider extends AbstractReadOnlyProvider implements BinaryProvider {
private final Class type;
private Spec super S> spec;
private S match;
private boolean ambiguous;
SingleElementProvider(Class type, Spec super S> spec) {
this.type = type;
this.spec = spec;
}
void selectNow() {
for (T element : elements) {
if (type.isInstance(element) && spec.isSatisfiedBy(type.cast(element))) {
if (match != null) {
ambiguous = true;
match = null;
break;
}
match = type.cast(element);
}
}
spec = null;
}
@Nullable
@Override
public Class getType() {
return type;
}
// Mix in some Groovy DSL support. Should decorate instead
public void configure(Closure> closure) {
configure(ConfigureUtil.configureUsing(closure));
}
@Override
public void configure(final Action super S> action) {
configureEach(new Action() {
@Override
public void execute(T t) {
if (match == t) {
action.execute(match);
}
}
});
}
@Override
public void whenFinalized(final Action super S> action) {
whenElementFinalized(new Action() {
@Override
public void execute(T t) {
if (match == t) {
action.execute(match);
}
}
});
}
@Nullable
@Override
public S getOrNull() {
if (ambiguous) {
throw new IllegalStateException("Found multiple elements");
}
return match;
}
}
private static class TypeFilteringAction implements Action {
private final Class type;
private final Action super S> action;
TypeFilteringAction(Class type, Action super S> action) {
this.type = type;
this.action = action;
}
@Override
public void execute(T t) {
if (type.isInstance(t)) {
action.execute(type.cast(t));
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy