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

org.flexiblepower.pythoncodegen.PythonTemplates Maven / Gradle / Ivy

/*-
 * #%L
 * dEF-Pi python service creation
 * %%
 * Copyright (C) 2017 - 2018 Flexible Power Alliance Network
 * %%
 * 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.
 * #L%
 */
package org.flexiblepower.pythoncodegen;

import java.io.IOException;
import java.text.DateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.flexiblepower.codegen.PluginUtils;
import org.flexiblepower.codegen.Templates;
import org.flexiblepower.codegen.model.InterfaceDescription;
import org.flexiblepower.codegen.model.InterfaceVersionDescription;
import org.flexiblepower.codegen.model.InterfaceVersionDescription.Type;
import org.flexiblepower.codegen.model.ServiceDescription;

/**
 * Templates
 *
 * @version 0.1
 * @since Jun 8, 2017
 */
public class PythonTemplates extends Templates {

    /**
     * Constant representing the code generator
     */
    private static final String GENERATOR_NAME = "Python code generator for dEF-Pi";

    /**
     * Create the object that provides the Templates for the python code generation for a service description
     *
     * @param descr The service description as parsed from the service.json file
     */
    public PythonTemplates(final ServiceDescription descr) {
        super(descr);
    }

    /**
     * Generate the main python file
     *
     * @return The string containing the content of __main__.py
     * @throws IOException When an exception occurs while reading the template
     */
    public String generateServiceMain() throws IOException {
        return this.generate("ServiceMain", null, null);
    }

    /**
     * Generate the contents for the service implementation file
     *
     * @return The code that implements the service for the project.
     * @throws IOException When an exception occurs while reading the template
     */
    public String generateServiceImplementation() throws IOException {
        return this.generate("ServiceImplementation", null, null);
    }

    /**
     * Generate the file contents for the pip requirements file
     *
     * @return The contents of the requirements.txt file
     * @throws IOException When an exception occurs while reading the template
     */
    public String generateRequirements() throws IOException {
        return this.generate("PipRequirements", null, null);
    }

    /**
     * Generate the contents for the abstract base class defining the connection handler for the specified dEF-Pi
     * interface version.
     *
     * @param itf The interface to generate the handler interface for
     * @param version The version of the interface to generate the code for
     * @return The code of the connection handler interface for the specified version of the interface
     * @throws IOException When an exception occurs while reading the template file
     */
    public String generateHandlerInterface(final InterfaceDescription itf, final InterfaceVersionDescription version)
            throws IOException {
        return this.generate("ConnectionHandlerInterface", itf, version);
    }

    /**
     * Generate the code that implements the connection handler for the specified dEF-Pi interface version.
     *
     * @param itf The interface to generate the handler implementation for
     * @param version The version of the interface to generate the code for
     * @return The code of the connection handler implementation for the specified version of the interface
     * @throws IOException When an exception occurs while reading the template file
     */
    public String generateHandlerImplementation(final InterfaceDescription itf,
            final InterfaceVersionDescription version) throws IOException {
        return this.generate("ConnectionHandlerClass", itf, version);
    }

    /**
     * Generate the code of the java interface that defines the manager for the specified dEF-Pi interface.
     *
     * @param itf The interface to generate the manager interface for
     * @return The code of the connection manager interface for the specified interface
     * @throws IOException When an exception occurs while reading the template file
     */
    public String generateManagerInterface(final InterfaceDescription itf) throws IOException {
        return this.generate("ManagerInterface", itf, null);
    }

    /**
     * Generate the code that implements the manager for the specified dEF-Pi interface.
     *
     * @param itf The interface to generate the manager implementation for
     * @return The code of the connection manager implementation for the specified interface
     * @throws IOException When an exception occurs while reading the template file
     */
    public String generateManagerImplementation(final InterfaceDescription itf) throws IOException {
        return this.generate("ManagerClass", itf, null);
    }

    /**
     * Generate a file based on the template and the provided interface description and version description
     *
     * @param templateName The template to use while creating the code
     * @param itf The interface to generate the code for
     * @param version The version of the interface to generate the code for
     * @return The filled-in template, which should provide valid java code
     * @throws IOException When an exception occurs while reading the template file
     */
    private String generate(final String templateName,
            final InterfaceDescription itf,
            final InterfaceVersionDescription version) throws IOException {
        final String template = this.getTemplate(templateName);

        final Map replaceMap = new HashMap<>();

        // Generic stuff that is the same everywhere
        String userName = System.getenv("USER");
        if ((userName == null) || userName.isEmpty()) {
            userName = System.getProperty("user.name");
        }
        replaceMap.put("username", userName);
        replaceMap.put("date", DateFormat.getDateTimeInstance().format(new Date()));
        replaceMap.put("generator", PythonTemplates.GENERATOR_NAME);

        replaceMap.put("service.class", PythonCodegenUtils.serviceImplClass(this.serviceDescription));
        replaceMap.put("service.version", this.serviceDescription.getVersion());
        replaceMap.put("service.name", this.serviceDescription.getName());

        // Build replaceMaps for the manager
        if (itf != null) {
            replaceMap.put("itf.manager.class", PythonCodegenUtils.managerClass(itf));
            replaceMap.put("itf.manager.interface", PythonCodegenUtils.managerInterface(itf));

            final Set definitions = new HashSet<>();
            final Set implementations = new HashSet<>();
            final Set itfimports = new HashSet<>();
            final Set itfitfimports = new HashSet<>();
            for (final InterfaceVersionDescription vitf : itf.getInterfaceVersions()) {
                final String interfaceClass = PythonCodegenUtils.connectionHandlerInterface(itf, vitf);
                final String implementationClass = PythonCodegenUtils.connectionHandlerClass(itf, vitf);
                final String interfaceVersionModule = PythonCodegenUtils.getVersion(vitf);

                final Map handlerReplace = new HashMap<>();
                handlerReplace.put("vitf.handler.interface", interfaceClass);
                handlerReplace.put("vitf.handler.class", implementationClass);
                handlerReplace.put("vitf.version", interfaceVersionModule);
                handlerReplace.put("vitf.version.builder", PythonCodegenUtils.builderFunctionName(vitf));

                definitions.add(this.replaceMap(this.getTemplate("BuilderDefinition"), handlerReplace));
                implementations.add(this.replaceMap(this.getTemplate("BuilderImplementation"), handlerReplace));

                itfimports.add(String.format("from .%s.%s import %s",
                        interfaceVersionModule,
                        implementationClass,
                        implementationClass));
                itfitfimports.add(
                        String.format("from .%s.%s import %s", interfaceVersionModule, interfaceClass, interfaceClass));
            }

            replaceMap.put("itf.manager.definitions", String.join("\n\n", definitions));
            replaceMap.put("itf.manager.implementations", String.join("\n\n", implementations));
            replaceMap.put("itf.manager.imports.interface", String.join("\n", itfitfimports));
            replaceMap.put("itf.manager.imports.implementation", String.join("\n", itfimports));
        } else {
            final Set managerImports = new HashSet<>();
            for (final InterfaceDescription descr : this.serviceDescription.getInterfaces()) {
                managerImports.add(String.format("from .%s.%s import %s",
                        PythonCodegenUtils.getInterfacePackage(descr),
                        PythonCodegenUtils.managerClass(descr),
                        PythonCodegenUtils.managerClass(descr)));

            }
            replaceMap.put("service.managerimports", String.join("\n", managerImports));

        }
        // Build replaceMaps for the interface versions
        if ((itf != null) && (version != null)) {
            replaceMap.put("vitf.handler.interface", PythonCodegenUtils.connectionHandlerInterface(itf, version));
            replaceMap.put("vitf.handler.class", PythonCodegenUtils.connectionHandlerClass(itf, version));

            replaceMap.put("itf.name", itf.getName());
            replaceMap.put("vitf.version", version.getVersionName());
            replaceMap.put("vitf.receivesHash", PluginUtils.getReceiveHash(version));
            replaceMap.put("vitf.sendsHash", PluginUtils.getSendHash(version));

            final Set recvClasses = new HashSet<>();
            for (final String type : version.getReceives()) {
                recvClasses.add(type);
            }
            replaceMap.put("vitf.receiveClasses", String.join(", ", recvClasses));

            final Set sendClasses = new HashSet<>();
            for (final String type : version.getSends()) {
                sendClasses.add(type);
            }
            replaceMap.put("vitf.sendClasses", String.join(", ", sendClasses));

            // Add handler definitions and implementations for the connection handlers (and implementations
            // respectively)
            final Set definitions = new HashSet<>();
            final Set implementations = new HashSet<>();
            for (final String type : version.getReceives()) {
                final Map handlerReplace = new HashMap<>();
                handlerReplace.put("handle.type", type);
                handlerReplace.put("handler.function", PythonCodegenUtils.typeHandlerFunction(type));

                definitions.add(this.replaceMap(this.getTemplate("HandlerDefinition"), handlerReplace));
                implementations.add(this.replaceMap(this.getTemplate("HandlerImplementation"), handlerReplace));
            }
            replaceMap.put("vitf.handler.definitions", String.join("\n\n", definitions));
            replaceMap.put("vitf.handler.implementations", String.join("\n\n", implementations));

            if (version.getType().equals(Type.PROTO)) {
                replaceMap.put("vitf.serializer", "proto");
            } else if (version.getType().equals(Type.XSD)) {
                replaceMap.put("vitf.serializer", "xsd");
            }

            // Add imports for the handlers
            final Set handlerImports = new HashSet<>();
            final Set interfaceImports = new HashSet<>();
            final String versionPackage = version.getModelPackageName().replaceAll("/", ".");
            for (final String type : version.getReceives()) {
                handlerImports.add(String.format("from %s import %s", versionPackage, type));
                interfaceImports.add(String.format("from %s import %s", versionPackage, type));
            }
            for (final String type : version.getSends()) {
                interfaceImports.add(String.format("from %s import %s", versionPackage, type));
            }

            replaceMap.put("vitf.handler.imports", String.join("\n", handlerImports));
            replaceMap.put("vitf.handler.interface.imports", String.join("\n", interfaceImports));
        }

        return this.replaceMap(template, replaceMap);
    }

    @Override
    protected String getDockerBaseImage(final String platform) {
        if (platform.equals("x86")) {
            return "python:3.5-slim";
        } else {
            return "armhf/python:3.5-alpine";
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy