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

com.fluxtion.compiler.EventProcessorConfig Maven / Gradle / Ivy

/*
 * Copyright (C) 2018 2024 gregory higgins.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the Server Side Public License, version 1,
 * as published by MongoDB, Inc.
 *
 * This program 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
 * Server Side Public License for more details.
 *
 * You should have received a copy of the Server Side Public License
 * along with this program.  If not, see
 * .
 */
package com.fluxtion.compiler;

import com.fluxtion.compiler.builder.callback.*;
import com.fluxtion.compiler.builder.context.EventProcessorContextFactory;
import com.fluxtion.compiler.builder.context.InstanceSupplierFactory;
import com.fluxtion.compiler.builder.factory.*;
import com.fluxtion.compiler.builder.filter.EventHandlerFilterOverride;
import com.fluxtion.compiler.builder.input.SubscriptionManagerFactory;
import com.fluxtion.compiler.builder.output.SinkPublisherFactory;
import com.fluxtion.compiler.builder.time.ClockFactory;
import com.fluxtion.compiler.generation.serialiser.*;
import com.fluxtion.runtime.audit.Auditor;
import com.fluxtion.runtime.audit.EventLogControlEvent.LogLevel;
import com.fluxtion.runtime.audit.EventLogManager;
import com.fluxtion.runtime.dataflow.function.MergeProperty;
import com.fluxtion.runtime.partition.LambdaReflection;
import com.fluxtion.runtime.service.ServiceRegistryNode;
import com.fluxtion.runtime.time.Clock;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import java.io.File;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URL;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.time.*;
import java.util.*;
import java.util.function.Function;

/**
 * Configuration used by Fluxtion event stream compiler at generation time to
 * control the processing logic of the {@link com.fluxtion.runtime.EventProcessor}
 *
 * @author Greg Higgins
 */
@ToString
public class EventProcessorConfig {

    private final Set> interfaces = new HashSet<>();
    private final Clock clock = Clock.DEFAULT_CLOCK;
    private final Map class2replace = new HashMap<>();
    private final Map filterMap = new HashMap<>();
    private final Map, Function> classSerializerMap = new HashMap<>();
    private String templateFile;
    private List nodeList;
    private HashMap publicNodes;
    private HashMap auditorMap;
    private NodeFactoryRegistration nodeFactoryRegistration;
    private RootNodeConfig rootNodeConfig;
    private boolean inlineEventHandling = false;
    private boolean supportDirtyFiltering = true;
    private boolean assignPrivateMembers = false;
    private boolean instanceOfDispatch = true;
    @Getter
    @Setter
    private boolean supportBufferAndTrigger = true;
    private DISPATCH_STRATEGY dispatchStrategy = DISPATCH_STRATEGY.INSTANCE_OF;
    private List compilerOptions = new ArrayList<>();

    public EventProcessorConfig() {
        clock();
        ServiceRegistryNode serviceRegistryNode = new ServiceRegistryNode();
        addAuditor(serviceRegistryNode, ServiceRegistryNode.NODE_NAME);
        addNode(serviceRegistryNode, ServiceRegistryNode.NODE_NAME);
        this.nodeFactoryRegistration = new NodeFactoryRegistration(NodeFactoryConfig.required.getFactoryClasses());
        classSerializerMap.put(String.class, BasicTypeSerializer::stringToSource);
        classSerializerMap.put(Character.class, BasicTypeSerializer::charToSource);
        classSerializerMap.put(char.class, BasicTypeSerializer::charToSource);
        classSerializerMap.put(Long.class, BasicTypeSerializer::longToSource);
        classSerializerMap.put(long.class, BasicTypeSerializer::longToSource);
        classSerializerMap.put(int.class, BasicTypeSerializer::intToSource);
        classSerializerMap.put(Integer.class, BasicTypeSerializer::intToSource);
        classSerializerMap.put(Short.class, BasicTypeSerializer::shortToSource);
        classSerializerMap.put(short.class, BasicTypeSerializer::shortToSource);
        classSerializerMap.put(Byte.class, BasicTypeSerializer::byteToSource);
        classSerializerMap.put(byte.class, BasicTypeSerializer::byteToSource);
        classSerializerMap.put(Double.class, BasicTypeSerializer::doubleToSource);
        classSerializerMap.put(double.class, BasicTypeSerializer::doubleToSource);
        classSerializerMap.put(Float.class, BasicTypeSerializer::floatToSource);
        classSerializerMap.put(float.class, BasicTypeSerializer::floatToSource);
        classSerializerMap.put(Boolean.class, BasicTypeSerializer::booleanToSource);
        classSerializerMap.put(boolean.class, BasicTypeSerializer::booleanToSource);
        classSerializerMap.put(Map.class, CollectionSerializer::mapToSource);
        classSerializerMap.put(List.class, CollectionSerializer::listToSource);
        classSerializerMap.put(Set.class, CollectionSerializer::setToSource);
        classSerializerMap.put(Duration.class, TimeSerializer::durationToSource);
        classSerializerMap.put(Instant.class, TimeSerializer::instantToSource);
        classSerializerMap.put(LocalDate.class, TimeSerializer::localDateToSource);
        classSerializerMap.put(LocalTime.class, TimeSerializer::localTimeToSource);
        classSerializerMap.put(LocalDateTime.class, TimeSerializer::localDateTimeToSource);
        classSerializerMap.put(Period.class, TimeSerializer::periodToSource);
        classSerializerMap.put(ZoneId.class, TimeSerializer::zoneIdToSource);
        classSerializerMap.put(ZonedDateTime.class, TimeSerializer::zoneDateTimeToSource);
        classSerializerMap.put(Date.class, TimeSerializer::dateToSource);
        classSerializerMap.put(File.class, IoSerializer::fileToSource);
        classSerializerMap.put(URI.class, IoSerializer::uriToSource);
        classSerializerMap.put(URL.class, IoSerializer::urlToSource);
        classSerializerMap.put(InetSocketAddress.class, IoSerializer::inetSocketAddressToSource);
        classSerializerMap.put(SimpleDateFormat.class, FormatSerializer::simpleDataFormatToSource);
        classSerializerMap.put(DateFormat.class, FormatSerializer::simpleDataFormatToSource);
        classSerializerMap.put(DecimalFormat.class, FormatSerializer::decimalFormatToSource);
        classSerializerMap.put(NumberFormat.class, FormatSerializer::decimalFormatToSource);
        classSerializerMap.put(Class.class, MetaSerializer::classToSource);
        classSerializerMap.put(MergeProperty.class, MetaSerializer::mergePropertyToSource);
        classSerializerMap.put(LambdaReflection.MethodReferenceReflection.class, MetaSerializer::methodReferenceToSource);
    }

    /**
     * Add a node to the SEP. The node will have private final scope, the
     * variable name of the node will be generated from {@link NodeNameProducer}
     * strategy.

* Fluxtion will check if this node is already in the node set and will * return the previously added node. * * @param The type of the node to add to the SEP * @param node the node instance to add * @return The de-duplicated added node */ @SuppressWarnings("unchecked") public T addNode(T node) { if (getNodeList() == null) { setNodeList(new ArrayList<>()); } if (!getNodeList().contains(node)) { getNodeList().add(node); return node; } return (T) getNodeList().get(getNodeList().indexOf(node)); } public void addNode(Object node, Object... nodeList) { addNode(node); Arrays.asList(nodeList).forEach(this::addNode); } /** * Add a node to the SEP. The node will have public final scope, the * variable name of the node will be generated from {@link NodeNameProducer} * strategy if the provided name is null.

* Fluxtion will check if this node is already in the node set and will * return the previously added node. * * @param The type of the node to add to the SEP * @param node the node instance to add * @param name the variable name of the node * @return The de-duplicated added node */ @SuppressWarnings("unchecked") public T addNode(T node, String name) { addNode(node); addPublicNode(node, name); return (T) getNodeList().get(getNodeList().indexOf(node)); } /** * Add a node to the SEP. The node will have public final scope, the * variable name of the node will be generated from {@link NodeNameProducer} * strategy if the provided name is null.

* Fluxtion will check if this node is already in the node set and will * return the previously added node. * * @param The type of the node to add to the SEP * @param node the node instance to add * @param name the variable name of the node * @return The de-duplicated added node */ public T addPublicNode(T node, String name) { if (getPublicNodes() == null) { setPublicNodes(new HashMap<>()); } getPublicNodes().put(node, name); return node; } // public void addNode(MethodReferenceReflection methodReference){ // // } /** * Adds an {@link Auditor} to this SEP. The Auditor will have public final * scope and can be accessed via the provided variable name. * * @param The type of the Auditor * @param listener Auditor instance * @param name public name of Auditor * @return the added Auditor */ public T addAuditor(T listener, String name) { if (getAuditorMap() == null) { setAuditorMap(new HashMap<>()); } getAuditorMap().put(name, listener); return listener; } /** * Maps a class name from one String to another in the generated output. * * @param originalFqn Class name to replace * @param mappedFqn Class name replacement */ public void mapClass(String originalFqn, String mappedFqn) { getClass2replace().put(originalFqn, mappedFqn); } /** * adds a clock to the generated SEP. * * @return the clock in generated SEP */ public Clock clock() { addAuditor(clock, "clock"); return clock; } /** * Add an {@link EventLogManager} auditor to the generated SEP. Specify * the level at which method tracing will take place. */ public void addEventAudit(LogLevel tracingLogLevel) { if (tracingLogLevel != null) { addAuditor(new EventLogManager().tracingOn(tracingLogLevel), EventLogManager.NODE_NAME); } } /** * Add an {@link EventLogManager} auditor to the generated SEP without method tracing */ public void addEventAudit() { addAuditor(new EventLogManager().tracingOff(), EventLogManager.NODE_NAME); } public void addEventAudit(LogLevel tracingLogLevel, boolean printEventToString) { addEventAudit(tracingLogLevel, printEventToString, true); } public void addEventAudit(LogLevel tracingLogLevel, boolean printEventToString, boolean printThreadName) { addAuditor( new EventLogManager() .tracingOn(tracingLogLevel) .printEventToString(printEventToString) .printThreadName(printThreadName), EventLogManager.NODE_NAME); } public void addInterfaceImplementation(Class clazz) { interfaces.add(clazz); } public Set> interfacesToImplement() { return interfaces; } /** * Users can override this method and add SEP description logic here. The * buildConfig method will be called by the Fluxtion generator at build * time. */ public void buildConfig() { } /** * the name of the template file to use as an input */ public String getTemplateFile() { return templateFile; } public void setTemplateFile(String templateFile) { this.templateFile = templateFile; } /** * the nodes included in this graph */ public List getNodeList() { return nodeList; } public void setNodeList(List nodeList) { this.nodeList = nodeList; } /** * Variable names overrides for public nodes, these will be well known and * addressable from outside the SEP. */ public HashMap getPublicNodes() { return publicNodes; } public T getNode(String name) { Object[] obj = new Object[1]; publicNodes.entrySet().stream() .filter(e -> e.getValue().equals(name)) .findFirst() .ifPresent(e -> obj[0] = e.getKey()); return (T) obj[0]; } public void setPublicNodes(HashMap publicNodes) { this.publicNodes = publicNodes; } public HashMap getAuditorMap() { return auditorMap; } public void setAuditorMap(HashMap auditorMap) { this.auditorMap = auditorMap; } /** * Node Factory configuration */ public NodeFactoryRegistration getNodeFactoryRegistration() { return nodeFactoryRegistration; } public void setNodeFactoryRegistration(NodeFactoryRegistration nodeFactoryRegistration) { //add defaults nodeFactoryRegistration.factoryClassSet.addAll(NodeFactoryConfig.required.getFactoryClasses()); this.nodeFactoryRegistration = nodeFactoryRegistration; } /** * Makes available in the graph an injectable instance that other nodes can inject see {@link com.fluxtion.runtime.annotations.builder.Inject}. * The factoryName parameter must match the factoryName attribute in the inject annotation *
     * {@literal }@Inject(factoryName = "someUniqueName")
     *  public RoomSensor roomSensor2;
     *
     * 
* If no inject annotations reference the instance it will not be added to the graph * * @param factoryName The unique name for this instance * @param injectionType The type of injection * @param injectableInstance The instance to inject * @param The concrete type of the injected instance * @param The type of the injected instance * @return */ public EventProcessorConfig registerInjectable(String factoryName, Class injectionType, S injectableInstance) { nodeFactoryRegistration.factorySet.add(new SingletonNodeFactory<>(injectableInstance, injectionType, factoryName)); return this; } /** * Makes available in the graph an injectable instance that other nodes can inject see {@link com.fluxtion.runtime.annotations.builder.Inject}. * The factoryName parameter must match the factoryName attribute in the inject annotation *
     * {@literal }@Inject(factoryName = "someUniqueName")
     *  public RoomSensor roomSensor2;
     *
     * 
* If no inject annotations reference the instance it will not be added to the graph * * @param factoryName The unique name for this instance * @param injectableInstance The instance to inject * @param The concrete type of the injected instance and the type of the injected instance * @return */ public EventProcessorConfig registerInjectable(String factoryName, T injectableInstance) { registerInjectable(factoryName, (Class) injectableInstance.getClass(), injectableInstance); return this; } public RootNodeConfig getRootNodeConfig() { return rootNodeConfig; } public void setRootNodeConfig(RootNodeConfig rootNodeConfig) { this.rootNodeConfig = rootNodeConfig; } /** * overrides the filter integer id's for a set of instances */ public Map getFilterMap() { return filterMap; } public void setFilterMap(Map filterMap) { this.filterMap.clear(); this.filterMap.putAll(filterMap); } /** * Overrides the filterId for any methods annotated with {@link com.fluxtion.runtime.annotations.OnEventHandler} in * an instance or for an {@link com.fluxtion.runtime.node.EventHandlerNode}. *

* If a single {@link com.fluxtion.runtime.annotations.OnEventHandler} annotated method needs to be overridden then * use {@link this#overrideOnEventHandlerFilterId(Object, Class, int)} * * @param eventHandler the event handler instance to override filterId * @param newFilterId the new filterId */ public void overrideOnEventHandlerFilterId(Object eventHandler, int newFilterId) { getFilterMap().put(eventHandler, newFilterId); } /** * Overrides the filterId for a method annotated with {@link com.fluxtion.runtime.annotations.OnEventHandler} in * an instance handling a particular event type. * * @param eventHandler the event handler instance to override filterId * @param eventClass The event handler methods of this type to override filterId * @param newFilterId the new filterId */ public void overrideOnEventHandlerFilterId(Object eventHandler, Class eventClass, int newFilterId) { getFilterMap().put(new EventHandlerFilterOverride(eventHandler, eventClass, newFilterId), newFilterId); } /** * Register a custom serialiser that maps a field to source at generation time * * @param classToSerialize the class type to support custom serialisation * @param serializationFunction The instance to source function * @return current {@link EventProcessorConfig} */ @SuppressWarnings("unchecked") public EventProcessorConfig addClassSerializer( Class classToSerialize, Function, String> serializationFunction) { classSerializerMap.put(classToSerialize, (Function) (Object) serializationFunction); return this; } public Map, Function> getClassSerializerMap() { return classSerializerMap; } /** * configures generated code to inline the event handling methods or not. */ public boolean isInlineEventHandling() { return inlineEventHandling; } public void setInlineEventHandling(boolean inlineEventHandling) { this.inlineEventHandling = inlineEventHandling; } /** * configures generated code to support dirty filtering */ public boolean isSupportDirtyFiltering() { return supportDirtyFiltering; } public void setSupportDirtyFiltering(boolean supportDirtyFiltering) { this.supportDirtyFiltering = supportDirtyFiltering; } /** * attempt to assign private member variables, some platforms will support * access to non-public scoped members. e.g. reflection utilities in Java. */ public boolean isAssignPrivateMembers() { return assignPrivateMembers; } public void setAssignPrivateMembers(boolean assignPrivateMembers) { this.assignPrivateMembers = assignPrivateMembers; } /** * Map an original fully qualified class name into a new value. Can be * useful if generated code wants to remove all dependencies to Fluxtion * classes and replaced with user classes. */ public Map getClass2replace() { return class2replace; } public boolean isInstanceOfDispatch() { return instanceOfDispatch; } public void setInstanceOfDispatch(boolean instanceOfDispatch) { this.instanceOfDispatch = instanceOfDispatch; } public DISPATCH_STRATEGY getDispatchStrategy() { return dispatchStrategy; } public void setDispatchStrategy(DISPATCH_STRATEGY dispatchStrategy) { Objects.requireNonNull(dispatchStrategy, "Dispatch strategy must be non null"); if (dispatchStrategy == DISPATCH_STRATEGY.PATTERN_MATCH) { enablePreviewFeatures(); javaTargetRelease("21"); } this.dispatchStrategy = dispatchStrategy; } public List getCompilerOptions() { return compilerOptions; } public void setCompilerOptions(List compilerOptions) { Objects.requireNonNull(compilerOptions); this.compilerOptions = compilerOptions; } public EventProcessorConfig enablePreviewFeatures() { compilerOptions.add("--enable-preview"); return this; } public EventProcessorConfig javaTargetRelease(String release) { Objects.requireNonNull(release); compilerOptions.add("--release"); compilerOptions.add(release); return this; } public enum DISPATCH_STRATEGY { CLASS_NAME, INSTANCE_OF, PATTERN_MATCH } enum NodeFactoryConfig { required( CallBackDispatcherFactory.class, CallbackNodeFactory.class, ClockFactory.class, InstanceSupplierFactory.class, DirtyStateMonitorFactory.class, EventDispatcherFactory.class, EventProcessorCallbackInternalFactory.class, EventProcessorContextFactory.class, NodeNameLookupFactory.class, SubscriptionManagerFactory.class, SinkPublisherFactory.class ); private final HashSet>> defaultFactories = new HashSet<>(); NodeFactoryConfig(Class>... factoryClasses) { Arrays.asList(factoryClasses).forEach(defaultFactories::add); } public Set>> getFactoryClasses() { return new HashSet<>(defaultFactories); } } }