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

org.praxislive.code.SharedCodeService Maven / Gradle / Ivy

Go to download

Forest-of-actors runtime supporting real-time systems and real-time recoding - bringing aspects of Erlang, Smalltalk and Extempore to Java.

There is a newer version: 6.0.0-beta1
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2022 Neil C Smith.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version 3 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
 * version 3 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License version 3
 * along with this work; if not, see http://www.gnu.org/licenses/
 *
 *
 * Please visit https://www.praxislive.org if you need additional information or
 * have any questions.
 */
package org.praxislive.code;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Stream;
import org.praxislive.core.ControlAddress;
import org.praxislive.core.ControlInfo;
import org.praxislive.core.services.LogBuilder;
import org.praxislive.core.services.LogLevel;
import org.praxislive.core.services.Service;
import org.praxislive.core.types.PMap;
import org.praxislive.core.types.PReference;

/**
 * A {@link Service} for handling shared code updates and creating dependent
 * {@link CodeContext}. Must be running in the same process as the components
 * due to task and result references. Should make use of a
 * {@link CodeCompilerService} implementation for compiling source code (which
 * does support other processes).
 */
public class SharedCodeService implements Service {

    public final static String NEW_SHARED = "new-shared";
    public final static ControlInfo NEW_SHARED_INFO
            = ControlInfo.createFunctionInfo(
                    List.of(PReference.info(Task.class)),
                    List.of(PReference.info(Result.class)),
                    PMap.EMPTY);

    @Override
    public Stream controls() {
        return Stream.of(NEW_SHARED);
    }

    @Override
    public ControlInfo getControlInfo(String control) {
        if (NEW_SHARED.equals(control)) {
            return NEW_SHARED_INFO;
        }
        throw new IllegalArgumentException();
    }

    /**
     * Task containing new shared code and dependents to be updated, for sending
     * to the SharedCodeService.
     */
    public static class Task {

        private final PMap sources;
        private final Map> dependents;
        private final LogLevel logLevel;

        /**
         * Create a Task.
         *
         * @param sources new shared code sources
         * @param dependents map of dependent tasks by address
         * @param logLevel logging level
         */
        public Task(PMap sources,
                Map> dependents,
                LogLevel logLevel) {
            this.sources = Objects.requireNonNull(sources);
            this.dependents = Map.copyOf(dependents);
            this.logLevel = logLevel;
        }

        /**
         * Get the shared code sources.
         *
         * @return sources
         */
        public PMap getSources() {
            return sources;
        }

        /**
         * Get the map of dependents.
         *
         * @return dependents
         */
        public Map> getDependents() {
            return dependents;
        }

        /**
         * Get the logging level.
         *
         * @return logging level
         */
        public LogLevel getLogLevel() {
            return logLevel;
        }

    }

    /**
     * Result with shared classes, dependent code contexts, and log.
     */
    public static class Result {

        private final ClassLoader sharedClasses;
        private final Map> dependents;
        private final LogBuilder log;

        /**
         * Create an empty Result.
         */
        public Result() {
            this.sharedClasses = null;
            this.dependents = Map.of();
            this.log = new LogBuilder(LogLevel.ERROR);
        }

        /**
         * Create a Result.
         *
         * @param sharedClasses new shared classes classloader
         * @param dependents map of dependent results
         * @param log log
         */
        public Result(ClassLoader sharedClasses,
                Map> dependents,
                LogBuilder log) {
            this.sharedClasses = Objects.requireNonNull(sharedClasses);
            this.dependents = Map.copyOf(dependents);
            this.log = Objects.requireNonNull(log);
        }

        /**
         * Get the shared classes classloader.
         *
         * @return shared classes
         */
        public ClassLoader getSharedClasses() {
            return sharedClasses;
        }

        /**
         * Get the map if dependent results.
         *
         * @return dependents
         */
        public Map> getDependents() {
            return dependents;
        }

        /**
         * Get the log
         *
         * @return log
         */
        public LogBuilder getLog() {
            return log;
        }

    }

    /**
     * A dependent task for recompiling a {@link CodeDelegate} against the new
     * shared code classes.
     *
     * @param  base delegate type
     */
    public static class DependentTask {

        private final CodeFactory factory;
        private final String existingSource;
        private final Class existingClass;

        /**
         * Create a DependentTask.
         *
         * @param factory code factory for delegate
         * @param existingSource existing source to recompile
         * @param existingClass existing class
         */
        public DependentTask(CodeFactory factory,
                String existingSource,
                Class existingClass) {
            this.factory = Objects.requireNonNull(factory);
            this.existingSource = Objects.requireNonNull(existingSource);
            this.existingClass = Objects.requireNonNull(existingClass);
        }

        /**
         * Get code factory.
         *
         * @return code factory
         */
        public CodeFactory getFactory() {
            return factory;
        }

        /**
         * Get the existing source.
         *
         * @return existing source
         */
        public String getExistingSource() {
            return existingSource;
        }

        /**
         * Get the existing class.
         *
         * @return existing class
         */
        public Class getExistingClass() {
            return existingClass;
        }

    }

    /**
     * A dependent result with new code context linked to new shared code
     * classes.
     *
     * @param  base delegate type
     */
    public static class DependentResult {

        private final CodeContext context;
        private final Class existing;

        /**
         * Create a DependentResult.
         *
         * @param context code context
         * @param existing the existing (previous) class
         */
        public DependentResult(CodeContext context,
                Class existing) {
            this.context = Objects.requireNonNull(context);
            this.existing = Objects.requireNonNull(existing);
        }

        /**
         * Get the code context.
         *
         * @return code context
         */
        public CodeContext getContext() {
            return context;
        }

        /**
         * Get the existing (previous) class. Used for validation.
         *
         * @return existing (previous) class
         */
        public Class getExisting() {
            return existing;
        }

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy