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

colesico.framework.service.codegen.parser.TeleFacadesParser Maven / Gradle / Ivy

/*
 * Copyright 20014-2018 Vladlen Larionov
 *             and others as noted
 *
 * 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 colesico.framework.service.codegen.parser;

import colesico.framework.assist.codegen.CodegenException;
import colesico.framework.assist.codegen.FrameworkAbstractParser;
import colesico.framework.assist.codegen.model.*;
import colesico.framework.service.Compound;
import colesico.framework.service.TeleMethodName;
import colesico.framework.service.TeleView;
import colesico.framework.service.codegen.model.*;

import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.*;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import java.util.*;

public final class TeleFacadesParser extends FrameworkAbstractParser {

    private final ProcessorContext context;

    public TeleFacadesParser(ProcessorContext context) {
        super(context.getProcessingEnv());
        this.context = context;
    }

    protected TeleVarElement createTeleVarElement(TeleMethodElement teleMethod, TeleVarElement parentTeleVar, Deque varStack) {

        VarElement var = varStack.peek(); // get stack head element (first element of dequeq)

        //================= Check composition or parameter
        AnnotationElement compounddAnn = var.getAnnotation(Compound.class);
        if (compounddAnn == null) {
            TeleParamElement teleParam = new TeleParamElement(var);
            teleMethod.linkVariable(teleParam);
            teleParam.setParentVariable(parentTeleVar);
            context.getModulatorKit().notifyLinkTeleParam(teleParam, varStack);
            return teleParam;
        }

        //=================== Create composition


        // Check recursive objects
        VarElement methodParam = varStack.peekLast(); // get element from stack tail  (last element of deque)
        varStack.pop();     // temporaty remove var from stack head   (first element of deque)
        for (VarElement ve : varStack) {
            if (ve.asType().toString().equals(var.asType().toString())) {
                TeleFacadeElement teleFacade = teleMethod.getParentTeleFacade();
                throw CodegenException.of().message("Recursive composition for: " +
                        var.asType().toString() + "->" + var.getName() +
                        " in: " +
                        teleFacade.getParentService().getOriginClass().asType().toString() +
                        "->" + teleMethod.getProxyMethod().getName() + "(..." +
                        methodParam.toString()
                        + "...) ")
                        .element(methodParam)
                        .build();
            }
        }
        varStack.push(var); // push var back to stack head

        TeleCompElement teleComp = new TeleCompElement(var);
        teleMethod.linkVariable(teleComp);

        // ============ Process fields

        // Retrieve class fields for composition
        // Filter fields to get only acceptable
        List fields = var.asClassType().asClassElement().getFieldsFiltered(
                f -> !f.unwrap().getModifiers().contains(Modifier.FINAL)
                        && !f.unwrap().getModifiers().contains(Modifier.STATIC)
                        && f.unwrap().asType().getKind().equals(TypeKind.DECLARED)
        );


        // Process fields
        AnnotationElement teleViewAnn = varStack.getFirst().getAnnotation(TeleView.class);
        Set masterViews = getTeleViewKeys(teleViewAnn);
        for (FieldElement field : fields) {
            // Check field by "TeleView"
            teleViewAnn = field.getAnnotation(TeleView.class);
            Set fieldViews = getTeleViewKeys(teleViewAnn);
            if (!inTeleView(masterViews, fieldViews)) {
                continue;
            }

            if (field.asClassType() == null) {
                throw CodegenException.of().message("Unsupported field type kind for tele-view " + var.asClassType().asClassElement().getName() + "->" + field.getName())
                        .element(field.unwrap())
                        .build();
            }

            varStack.push(field);
            TeleVarElement teleVar = createTeleVarElement(teleMethod, teleComp, varStack);
            varStack.pop();
            teleComp.addVariable(teleVar);
        }

        return teleComp;
    }

    protected void addTeleMethodParams(TeleMethodElement teleMethod) {
        MethodElement method = teleMethod.getProxyMethod().getOriginMethod();
        for (ParameterElement param : method.getParameters()) {
            Deque varStack = new ArrayDeque<>();
            if (param.asClassType() == null) {
                throw CodegenException.of().message("Unsupported parameter type kind for tele-method " + teleMethod.getName() + "(..." + param.getName() + "...)")
                        .element(param.unwrap())
                        .build();
            }
            varStack.push(param);
            TeleVarElement teleParam = createTeleVarElement(teleMethod, null, varStack);
            teleMethod.addParameter(teleParam);
        }
    }

    protected void addTeleMethods(TeleFacadeElement teleFacade) {
        ServiceElement service = teleFacade.getParentService();
        for (ProxyMethodElement proxyMethod : service.getProxyMethods()) {
            if (proxyMethod.isLocal()) {
                continue;
            }
            AnnotationElement teleMethodNameAnn = proxyMethod.getOriginMethod().getAnnotation(TeleMethodName.class);
            final String teleMethodName;
            if (teleMethodNameAnn != null) {
                teleMethodName = teleMethodNameAnn.unwrap().value();
            } else {
                teleMethodName = proxyMethod.getName();
            }
            TeleMethodElement teleMethod = new TeleMethodElement(teleMethodName, proxyMethod);
            teleFacade.addTeleMethod(teleMethod);
            context.getModulatorKit().notifyAddTeleMethod(teleMethod);
            addTeleMethodParams(teleMethod);
        }
    }

    public void parseTeleFacades(ServiceElement service) {
        for (TeleFacadeElement teleFacade : service.getTeleFacades()) {
            addTeleMethods(teleFacade);
            context.getModulatorKit().notifyTeleFacadeParsed(teleFacade);
        }
    }

    private Set getTeleViewKeys(AnnotationElement teleViewAnnotation) {
        Set result = new HashSet<>();
        if (teleViewAnnotation == null) {
            return result;
        }
        TypeMirror[] keys = teleViewAnnotation.getValueTypeMirrors(a -> a.value());
        for (TypeMirror k : keys) {
            result.add(k.toString());
        }
        return result;
    }


    private boolean inTeleView(Set masterViews, Set fieldViews) {
        if (masterViews.isEmpty()) {
            return true;
        }
        for (String mv : masterViews) {
            if (fieldViews.contains(mv)) {
                return true;
            }
        }
        return false;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy