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

org.praxislive.project.GraphElement 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-beta2
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 2024 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.project;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.SequencedMap;
import java.util.SequencedSet;
import java.util.Set;
import org.praxislive.core.ComponentAddress;
import org.praxislive.core.ComponentType;
import org.praxislive.core.OrderedMap;
import org.praxislive.core.OrderedSet;
import org.praxislive.core.Value;
import org.praxislive.core.syntax.Token;
import org.praxislive.core.syntax.Tokenizer;

/**
 * Elements of a graph tree.
 */
public sealed abstract class GraphElement {

    private GraphElement() {
    }

    /**
     * Create a Command element from the given script line. The command must be
     * a single line of script with a plain first token.
     *
     * @param command script line
     * @return command element
     * @throws IllegalArgumentException if the command fails to parse according
     * to the rules
     */
    public static Command command(String command) {
        Iterator itr = new Tokenizer(command).iterator();
        List tokens = new ArrayList<>();
        while (itr.hasNext()) {
            Token token = itr.next();
            if (tokens.isEmpty()) {
                if (token.getType() != Token.Type.PLAIN) {
                    throw new IllegalArgumentException("First token of a command must be plain");
                }
            }
            if (token.getType() == Token.Type.COMMENT) {
                throw new IllegalArgumentException("Invalid command - contains a comment");
            } else if (token.getType() == Token.Type.EOL) {
                break;
            }
            tokens.add(token);
        }
        if (itr.hasNext()) {
            throw new IllegalArgumentException("Invalid command - tokens found after EOL");
        }
        return new Command(command, tokens);
    }

    /**
     * Create a Comment element from the given text.
     *
     * @param text comment text
     * @return comment element
     */
    public static Comment comment(String text) {
        return new Comment(text);
    }

    /**
     * Create a Connection element between the given source component ID and
     * port ID, and target component ID and port ID.
     *
     * @param sourceComponent source component ID
     * @param sourcePort source port ID
     * @param targetComponent target component ID
     * @param targetPort target port ID
     * @return connection element
     */
    public static Connection connection(String sourceComponent, String sourcePort,
            String targetComponent, String targetPort) {
        return new GraphElement.Connection(sourceComponent, sourcePort, targetComponent, targetPort);
    }

    /**
     * Create a property element of the given value.
     *
     * @param value property value
     * @return property element
     */
    public static Property property(Value value) {
        return new Property(value);
    }

    static Component component(ComponentType type,
            List comments,
            Map properties,
            Map children,
            Set connections) {
        return new Component(type, comments, properties, children, connections);
    }

    static Root root(String id, ComponentType type,
            List comments,
            List commands,
            Map properties,
            Map children,
            Set connections) {
        return new Root(id, type, comments, commands, properties, children, connections);
    }

    /**
     * A component element. A component has a type, and may have associated
     * comments, properties, children and/or connections.
     * 

* To create a Component element, see {@link GraphBuilder}. */ public static sealed class Component extends GraphElement { private final ComponentType type; private final List comments; private final OrderedMap properties; private final OrderedMap children; private final OrderedSet connections; private Component(ComponentType type, List comments, Map properties, Map children, Set connections) { this.type = Objects.requireNonNull(type); this.comments = List.copyOf(comments); this.properties = OrderedMap.copyOf(properties); this.children = OrderedMap.copyOf(children); this.connections = OrderedSet.copyOf(connections); } /** * Component type. * * @return type */ public ComponentType type() { return type; } /** * Immutable list of comment elements. * * @return comments */ public List comments() { return comments; } /** * Immutable ordered map of property elements by ID. * * @return properties */ public SequencedMap properties() { return properties; } /** * Immutable ordered map of child component elements by ID. * * @return children */ public SequencedMap children() { return children; } /** * Immutable ordered set of connection elements. * * @return connections */ public SequencedSet connections() { return connections; } @Override public int hashCode() { return Objects.hash(type, comments, properties, children, connections); } @Override public boolean equals(Object obj) { return obj == this || obj instanceof Component c && c.getClass() == Component.class && Objects.equals(this.type, c.type) && Objects.equals(this.comments, c.comments) && Objects.equals(this.properties, c.properties) && Objects.equals(this.children, c.children) && Objects.equals(this.connections, c.connections); } @Override public String toString() { return "Component{" + "type=" + type + ",\ncomments=" + comments + ",\nproperties=" + properties + ",\nchildren=" + children + ",\nconnections=" + connections + "}"; } } /** * A root component element. A normal root component has a type and ID, and * may have associated comments, commands, properties, children and/or * connections. A synthetic root is used for subgraphs, and has an empty ID * and no properties. *

* To create a Root element, see {@link GraphBuilder}. */ public static final class Root extends Component { static final ComponentType SYNTHETIC = ComponentType.of("root:synthetic"); private final String id; private final List commands; private Root(String id, ComponentType type, List comments, List commands, Map properties, Map children, Set connections) { super(type, comments, properties, children, connections); if (id.isEmpty()) { if (!SYNTHETIC.equals(type)) { throw new IllegalArgumentException("Invalid type for synthetic root"); } this.id = ""; } else { if (!ComponentAddress.isValidID(id)) { throw new IllegalArgumentException("Invalid root ID"); } this.id = id; } this.commands = List.copyOf(commands); } /** * Root ID. * * @return ID */ public String id() { return id; } /** * Immutable list of commands. * * @return commands */ public List commands() { return commands; } /** * Query whether the root element is synthetic. * * @return true if synthetic */ public boolean isSynthetic() { return id.isEmpty(); } @Override public int hashCode() { return Objects.hash(id, commands, type(), comments(), properties(), children(), connections()); } @Override public boolean equals(Object obj) { return obj == this || obj instanceof Root r && r.getClass() == Root.class && Objects.equals(id, r.id) && Objects.equals(commands, r.commands) && Objects.equals(this.type(), r.type()) && Objects.equals(this.comments(), r.comments()) && Objects.equals(this.properties(), r.properties()) && Objects.equals(this.children(), r.children()) && Objects.equals(this.connections(), r.connections()); } @Override public String toString() { return "Root{" + "id=" + id + ",\ncommands=" + commands + "type=" + type() + ",\ncomments=" + comments() + ",\nproperties=" + properties() + ",\nchildren=" + children() + ",\nconnections=" + connections() + "}"; } } public static final class Command extends GraphElement { private final String command; private final List tokens; Command(String command, List tokens) { this.command = Objects.requireNonNull(command); this.tokens = List.copyOf(tokens); } public String command() { return command; } public List tokens() { return tokens; } @Override public int hashCode() { return Objects.hashCode(command); } @Override public boolean equals(Object obj) { return obj == this || obj instanceof Command c && Objects.equals(this.command, c.command); } @Override public String toString() { return "Command{" + "command=" + command + "}"; } } public static final class Comment extends GraphElement { private final String text; private Comment(String text) { this.text = Objects.requireNonNull(text); } public String text() { return text; } @Override public int hashCode() { return Objects.hashCode(text); } @Override public boolean equals(Object obj) { return obj == this || obj instanceof Comment c && Objects.equals(this.text, c.text); } @Override public String toString() { return "Comment{" + "text=" + text + "}"; } } public static final class Property extends GraphElement { private final Value value; private Property(Value value) { this.value = Objects.requireNonNull(value); } public Value value() { return value; } @Override public int hashCode() { return Objects.hashCode(value); } @Override public boolean equals(Object obj) { return obj == this || obj instanceof Property p && Objects.equals(this.value, p.value); } @Override public String toString() { return "Property{" + "value=" + value + "}"; } } public static final class Connection extends GraphElement { private final org.praxislive.core.Connection value; private Connection(String sourceComponent, String sourcePort, String targetComponent, String targetPort) { value = org.praxislive.core.Connection.of(sourceComponent, sourcePort, targetComponent, targetPort); } public String sourceComponent() { return value.sourceComponent(); } public String sourcePort() { return value.sourcePort(); } public String targetComponent() { return value.targetComponent(); } public String targetPort() { return value.targetPort(); } @Override public int hashCode() { return Objects.hash(value); } @Override public boolean equals(Object obj) { return obj == this || obj instanceof Connection c && Objects.equals(this.value, c.value); } @Override public String toString() { return "Connection{" + "sourceComponent=" + sourceComponent() + ", sourcePort=" + sourcePort() + ", targetComponent=" + targetComponent() + ", targetPort=" + targetPort() + "}"; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy