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

org.gradle.model.internal.manage.schema.extract.ScalarCollectionNodeInitializerExtractionStrategy Maven / Gradle / Ivy

There is a newer version: 8.11.1
Show newest version
/*
 * Copyright 2015 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.model.internal.manage.schema.extract;

import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import org.gradle.internal.Cast;
import org.gradle.model.internal.core.ModelPath;
import org.gradle.model.internal.core.ModelViewState;
import org.gradle.model.internal.core.MutableModelNode;
import org.gradle.model.internal.core.NodeInitializer;
import org.gradle.model.internal.core.NodeInitializerContext;
import org.gradle.model.internal.core.TypeCompatibilityModelProjectionSupport;
import org.gradle.model.internal.core.rule.describe.ModelRuleDescriptor;
import org.gradle.model.internal.inspect.ModelElementProjection;
import org.gradle.model.internal.inspect.ProjectionOnlyNodeInitializer;
import org.gradle.model.internal.manage.schema.CollectionSchema;
import org.gradle.model.internal.manage.schema.ScalarValueSchema;
import org.gradle.model.internal.type.ModelType;
import org.gradle.model.internal.type.ModelTypes;

import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;

public class ScalarCollectionNodeInitializerExtractionStrategy extends CollectionNodeInitializerExtractionSupport {
    public final static List> TYPES = ImmutableList.>of(
        ModelType.of(List.class),
        ModelType.of(Set.class)
    );

    @Override
    protected  NodeInitializer extractNodeInitializer(CollectionSchema schema, NodeInitializerContext context) {
        ModelType type = schema.getType();
        Class rawClass = type.getRawClass();
        ModelType rawCollectionType = ModelType.of(rawClass);
        if (TYPES.contains(rawCollectionType) && (schema.getElementTypeSchema() instanceof ScalarValueSchema)) {
            Optional propertyContext = context.getPropertyContextOptional();
            boolean writable = !propertyContext.isPresent() || propertyContext.get().isWritable();
            if (schema.getType().getRawClass() == List.class) {
                return new ProjectionOnlyNodeInitializer(
                    ScalarCollectionModelProjection.forList(schema.getElementType(), !writable),
                    new ModelElementProjection(schema.getType())
                );
            } else {
                return new ProjectionOnlyNodeInitializer(
                    ScalarCollectionModelProjection.forSet(schema.getElementType(), !writable),
                    new ModelElementProjection(schema.getType())
                );
            }
        }
        return null;
    }

    @Override
    public Iterable> supportedTypes() {
        return ImmutableList.copyOf(TYPES);
    }

    private abstract static class ScalarCollectionModelProjection> extends TypeCompatibilityModelProjectionSupport {

        public ScalarCollectionModelProjection(ModelType type) {
            super(type);
        }

        @Override
        public Optional getValueDescription(MutableModelNode modelNodeInternal) {
            Collection values = modelNodeInternal.asImmutable(getType(), null).getInstance();
            if (values == null) {
                return Optional.of("null");
            }
            return Optional.of(values.toString());
        }

        @Override
        protected abstract ScalarCollectionModelView toView(MutableModelNode modelNode, ModelRuleDescriptor ruleDescriptor, boolean readOnly);

        public static  ScalarCollectionModelProjection> forList(final ModelType elementType, final boolean readOnly) {
            return new ScalarCollectionModelProjection>(ModelTypes.list(elementType)) {
                @Override
                protected ScalarCollectionModelView> toView(MutableModelNode modelNode, ModelRuleDescriptor ruleDescriptor, boolean mutable) {
                    return new ListModelView(modelNode.getPath(), elementType, modelNode, ruleDescriptor, readOnly, mutable);
                }
            };
        }

        public static  ScalarCollectionModelProjection> forSet(final ModelType elementType, final boolean readOnly) {
            return new ScalarCollectionModelProjection>(ModelTypes.set(elementType)) {
                @Override
                protected ScalarCollectionModelView> toView(MutableModelNode modelNode, ModelRuleDescriptor ruleDescriptor, boolean mutable) {
                    return new SetModelView(modelNode.getPath(), elementType, modelNode, ruleDescriptor, readOnly, mutable);
                }
            };
        }
    }

    private static class ListModelView extends ScalarCollectionModelView> {

        public ListModelView(ModelPath path, ModelType elementType, MutableModelNode modelNode, ModelRuleDescriptor descriptor, boolean overwritable, boolean mutable) {
            super(path, ModelTypes.list(elementType), elementType, modelNode, descriptor, overwritable, mutable);
        }

        @Override
        protected List initialValue() {
            return new LinkedList();
        }

        @Override
        protected List toMutationSafe(Collection backingCollection) {
            return new ListBackedCollection(Cast.>uncheckedCast(backingCollection), state, elementType);
        }
    }

    private static class SetModelView extends ScalarCollectionModelView> {

        public SetModelView(ModelPath path, ModelType elementType, MutableModelNode modelNode, ModelRuleDescriptor descriptor, boolean overwritable, boolean mutable) {
            super(path, ModelTypes.set(elementType), elementType, modelNode, descriptor, overwritable, mutable);
        }

        @Override
        protected Set initialValue() {
            return new LinkedHashSet();
        }

        @Override
        protected Set toMutationSafe(Collection backingCollection) {
            return new SetBackedCollection(Cast.>uncheckedCast(backingCollection), state, elementType);
        }
    }

    private abstract static class MutationSafeCollection implements Collection {
        private final Collection delegate;
        private final ModelViewState state;
        private final ModelType elementType;

        public MutationSafeCollection(Collection delegate, ModelViewState state, ModelType elementType) {
            this.delegate = delegate;
            this.state = state;
            this.elementType = elementType;
        }

        public Collection getDelegate(boolean forMutation) {
            if (forMutation) {
                state.assertCanMutate();
            }
            return delegate;
        }

        protected void validateElementType(Object o) {
            if (o != null) {
                ModelType obType = ModelType.of(o.getClass());
                if (!obType.equals(elementType)) {
                    throw new IllegalArgumentException(String.format("Cannot add an element of type %s to a collection of %s", obType, elementType));
                }
            }
        }

        protected void validateCollection(Collection c) {
            for (T element : c) {
                validateElementType(element);
            }
        }

        @Override
        public boolean add(T t) {
            validateElementType(t);
            return getDelegate(true).add(t);
        }

        @Override
        public boolean addAll(Collection c) {
            validateCollection(c);
            return getDelegate(true).addAll(c);
        }

        @Override
        public void clear() {
            getDelegate(true).clear();
        }

        @Override
        public boolean contains(Object o) {
            return getDelegate(false).contains(o);
        }

        @Override
        public boolean containsAll(Collection c) {
            return getDelegate(false).containsAll(c);
        }

        @Override
        public boolean equals(Object o) {
            return getDelegate(false).equals(o);
        }

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

        @Override
        public boolean isEmpty() {
            return getDelegate(false).isEmpty();
        }

        @Override
        public Iterator iterator() {
            return new MutationSafeIterator(getDelegate(false).iterator());
        }

        @Override
        public boolean remove(Object o) {
            return getDelegate(true).remove(o);
        }

        @Override
        public boolean removeAll(Collection c) {
            return getDelegate(true).removeAll(c);
        }

        @Override
        public boolean retainAll(Collection c) {
            return getDelegate(true).retainAll(c);
        }

        @Override
        public int size() {
            return getDelegate(false).size();
        }

        @Override
        public Object[] toArray() {
            return getDelegate(false).toArray();
        }

        @Override
        public  T[] toArray(T[] a) {
            return getDelegate(false).toArray(a);
        }

        private final class MutationSafeIterator implements Iterator {
            private final Iterator delegate;

            private MutationSafeIterator(Iterator delegate) {
                this.delegate = delegate;
            }

            @Override
            public boolean hasNext() {
                return delegate.hasNext();
            }

            @Override
            public T next() {
                return delegate.next();
            }

            @Override
            public void remove() {
                state.assertCanMutate();
                delegate.remove();
            }
        }

        @Override
        public String toString() {
            return delegate.toString();
        }
    }

    private static class ListBackedCollection extends MutationSafeCollection implements List {
        public ListBackedCollection(List delegate, ModelViewState state, ModelType elementType) {
            super(delegate, state, elementType);
        }

        @Override
        public void add(int index, T element) {
            validateElementType(element);
            ((List)getDelegate(true)).add(index, element);
        }


        @Override
        public boolean addAll(int index, Collection c) {
            validateCollection(c);
            return ((List)getDelegate(true)).addAll(index, c);
        }

        @Override
        public T get(int index) {
            return ((List)getDelegate(false)).get(index);
        }

        @Override
        public int indexOf(Object o) {
            return ((List)getDelegate(false)).indexOf(o);
        }

        @Override
        public int lastIndexOf(Object o) {
            return ((List)getDelegate(false)).lastIndexOf(o);
        }

        @Override
        public ListIterator listIterator() {
            return ((List)getDelegate(false)).listIterator();
        }

        @Override
        public ListIterator listIterator(int index) {
            return ((List)getDelegate(false)).listIterator(index);
        }

        @Override
        public T remove(int index) {
            return ((List)getDelegate(true)).remove(index);
        }

        @Override
        public List subList(int fromIndex, int toIndex) {
            throw new UnsupportedOperationException();
        }

        @Override
        public T set(int index, T element) {
            validateElementType(element);
            return ((List)getDelegate(true)).set(index, element);
        }
    }

    private static class SetBackedCollection extends MutationSafeCollection implements Set {

        public SetBackedCollection(Set delegate, ModelViewState state, ModelType elementType) {
            super(delegate, state, elementType);
        }

    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy