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

cool.klass.model.meta.domain.KlassImpl Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2024 Craig Motlin
 *
 * 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 cool.klass.model.meta.domain;

import java.util.Objects;
import java.util.Optional;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import cool.klass.model.meta.domain.api.Classifier;
import cool.klass.model.meta.domain.api.Element;
import cool.klass.model.meta.domain.api.Klass;
import cool.klass.model.meta.domain.api.NamedElement;
import cool.klass.model.meta.domain.api.property.AssociationEnd;
import cool.klass.model.meta.domain.api.property.DataTypeProperty;
import cool.klass.model.meta.domain.api.property.ReferenceProperty;
import cool.klass.model.meta.domain.api.source.KlassWithSourceCode;
import cool.klass.model.meta.domain.api.source.SourceCode;
import cool.klass.model.meta.domain.api.source.SourceCode.SourceCodeBuilder;
import cool.klass.model.meta.domain.property.AssociationEndImpl.AssociationEndBuilder;
import cool.klass.model.meta.grammar.KlassParser.ClassDeclarationContext;
import cool.klass.model.meta.grammar.KlassParser.IdentifierContext;
import org.eclipse.collections.api.factory.Lists;
import org.eclipse.collections.api.list.ImmutableList;
import org.eclipse.collections.api.map.ImmutableMap;

public final class KlassImpl
        extends AbstractClassifier
        implements KlassWithSourceCode
{
    private final boolean isAbstract;
    private final boolean isUser;
    private final boolean isTransient;

    private ImmutableList        declaredAssociationEnds;
    private ImmutableMap declaredAssociationEndsByName;
    private ImmutableList        associationEnds;
    private ImmutableMap associationEndsByName;

    @Nonnull
    private Optional versionProperty   = Optional.empty();
    @Nonnull
    private Optional versionedProperty = Optional.empty();

    private Optional      superClass;
    private ImmutableList subClasses;

    private KlassImpl(
            @Nonnull ClassDeclarationContext elementContext,
            @Nonnull Optional macroElement,
            @Nullable SourceCode sourceCode,
            int ordinal,
            @Nonnull IdentifierContext nameContext,
            @Nonnull String packageName,
            boolean isAbstract,
            boolean isUser,
            boolean isTransient)
    {
        super(elementContext, macroElement, sourceCode, ordinal, nameContext, packageName);
        this.isAbstract  = isAbstract;
        this.isUser      = isUser;
        this.isTransient = isTransient;
    }

    @Nonnull
    @Override
    public ClassDeclarationContext getElementContext()
    {
        return (ClassDeclarationContext) super.getElementContext();
    }

    @Override
    @Nonnull
    public Optional getVersionProperty()
    {
        return this.versionProperty;
    }

    @Override
    @Nonnull
    public Optional getVersionedProperty()
    {
        return this.versionedProperty;
    }

    @Override
    public boolean isAbstract()
    {
        return this.isAbstract;
    }

    @Override
    public boolean isUser()
    {
        return this.isUser;
    }

    @Override
    public boolean isTransient()
    {
        return this.isTransient;
    }

    private void setDeclaredAssociationEnds(ImmutableList declaredAssociationEnds)
    {
        if (this.declaredAssociationEnds != null)
        {
            throw new IllegalStateException();
        }
        this.declaredAssociationEnds       = Objects.requireNonNull(declaredAssociationEnds);
        this.declaredAssociationEndsByName = this.declaredAssociationEnds.groupByUniqueKey(AssociationEnd::getName);
    }

    @Override
    public ImmutableList getDeclaredAssociationEnds()
    {
        return Objects.requireNonNull(this.declaredAssociationEnds);
    }

    @Override
    public AssociationEnd getDeclaredAssociationEndByName(String name)
    {
        return this.declaredAssociationEndsByName.get(name);
    }

    private void setAssociationEnds(ImmutableList associationEnds)
    {
        if (this.associationEnds != null)
        {
            throw new IllegalStateException();
        }
        this.associationEnds       = Objects.requireNonNull(associationEnds);
        this.associationEndsByName = this.associationEnds.groupByUniqueKey(AssociationEnd::getName);

        this.versionProperty   = this.associationEnds.detectOptional(AssociationEnd::isVersion);
        this.versionedProperty = this.associationEnds.detectOptional(AssociationEnd::isVersioned);
    }

    @Override
    public ImmutableList getAssociationEnds()
    {
        return Objects.requireNonNull(this.associationEnds);
    }

    @Override
    public AssociationEnd getAssociationEndByName(String name)
    {
        return this.associationEndsByName.get(name);
    }

    @Override
    @Nonnull
    public Optional getSuperClass()
    {
        return this.superClass;
    }

    private void setSuperClass(Optional superClass)
    {
        if (this.superClass != null)
        {
            throw new IllegalStateException();
        }
        this.superClass = Objects.requireNonNull(superClass);
    }

    @Override
    public ImmutableList getSubClasses()
    {
        return Objects.requireNonNull(this.subClasses);
    }

    public void setSubClasses(ImmutableList subClasses)
    {
        if (this.subClasses != null)
        {
            throw new IllegalStateException();
        }
        this.subClasses = Objects.requireNonNull(subClasses);
    }

    public static final class KlassBuilder
            extends ClassifierBuilder
    {
        private final boolean isAbstract;
        private final boolean isUser;
        private final boolean isTransient;

        @Nullable
        private ImmutableList declaredAssociationEnds;

        private Optional      superClass;
        private ImmutableList subClasses;

        public KlassBuilder(
                @Nonnull ClassDeclarationContext elementContext,
                @Nonnull Optional> macroElement,
                @Nullable SourceCodeBuilder sourceCode,
                int ordinal,
                @Nonnull IdentifierContext nameContext,
                @Nonnull String packageName,
                boolean isAbstract,
                boolean isUser,
                boolean isTransient)
        {
            super(elementContext, macroElement, sourceCode, ordinal, nameContext, packageName);
            this.isAbstract  = isAbstract;
            this.isUser      = isUser;
            this.isTransient = isTransient;
        }

        public void setDeclaredAssociationEnds(@Nonnull ImmutableList declaredAssociationEnds)
        {
            if (this.declaredAssociationEnds != null)
            {
                throw new IllegalStateException();
            }
            this.declaredAssociationEnds = Objects.requireNonNull(declaredAssociationEnds);
        }

        @Override
        @Nonnull
        protected KlassImpl buildUnsafe()
        {
            return new KlassImpl(
                    (ClassDeclarationContext) this.elementContext,
                    this.macroElement.map(ElementBuilder::getElement),
                    this.sourceCode.build(),
                    this.ordinal,
                    this.getNameContext(),
                    this.packageName,
                    this.isAbstract,
                    this.isUser,
                    this.isTransient);
        }

        public void setSuperClass(@Nonnull Optional superClass)
        {
            if (this.superClass != null)
            {
                throw new IllegalStateException();
            }
            this.superClass = Objects.requireNonNull(superClass);
        }

        public void setSubClassBuilders(ImmutableList subClasses)
        {
            if (this.subClasses != null)
            {
                throw new IllegalStateException();
            }
            this.subClasses = Objects.requireNonNull(subClasses);
        }

        @Override
        public void build2()
        {
            super.build2();

            ImmutableList declaredAssociationEnds = this.declaredAssociationEnds
                    .collect(AssociationEndBuilder::getElement)
                    .toImmutable();
            this.element.setDeclaredAssociationEnds(declaredAssociationEnds);

            Optional maybeSuperClass = this.superClass.map(ElementBuilder::getElement);
            this.element.setSuperClass(maybeSuperClass);
            ImmutableList subClasses = this.subClasses.collect(ElementBuilder::getElement);
            this.element.setSubClasses(subClasses);

            ImmutableList associationEnds = maybeSuperClass
                    .map(Klass::getAssociationEnds)
                    .orElseGet(Lists.immutable::empty)
                    .newWithAll(declaredAssociationEnds)
                    .toReversed()
                    .distinctBy(NamedElement::getName)
                    .toReversed();

            this.element.setAssociationEnds(associationEnds);
        }

        @Override
        protected ImmutableList getDataTypeProperties()
        {
            ImmutableList declaredDataTypeProperties = this.declaredDataTypeProperties
                    .collect(property -> property.getElement());

            ImmutableList interfaceProperties = this.declaredInterfaces
                    .collect(ElementBuilder::getElement)
                    .flatCollect(Classifier::getDataTypeProperties)
                    .toImmutable();

            ImmutableList superClassProperties = this.superClass
                    .map(ElementBuilder::getElement)
                    .map(Classifier::getDataTypeProperties)
                    .orElseGet(Lists.immutable::empty);

            ImmutableList allDataTypeProperties = interfaceProperties
                    .newWithAll(superClassProperties)
                    .newWithAll(declaredDataTypeProperties);

            ImmutableList result = allDataTypeProperties
                    .toReversed()
                    .distinctBy(NamedElement::getName)
                    .toReversed();

            return result;
        }

        @Override
        protected ImmutableList getReferenceProperties()
        {
            ImmutableList declaredReferenceProperties = this.declaredReferenceProperties
                    .collect(property -> property.getElement());

            ImmutableList superClassProperties = this.superClass
                    .map(KlassBuilder::getReferenceProperties)
                    .orElseGet(Lists.immutable::empty);

            ImmutableList interfaceProperties = this.declaredInterfaces

                    .collect(ElementBuilder::getElement)
                    .flatCollect(Classifier::getReferenceProperties)
                    .toImmutable();

            ImmutableList allReferenceProperties = interfaceProperties
                    .newWithAll(superClassProperties)
                    .newWithAll(declaredReferenceProperties);

            ImmutableList result = allReferenceProperties
                    .toReversed()
                    .distinctBy(NamedElement::getName)
                    .toReversed();

            return result;
        }

        @Override
        public KlassImpl getType()
        {
            return Objects.requireNonNull(this.element);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy