Skip to content

Implement immutable DecisionGraph for decision table components #169

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions src/main/java/ru/ewc/decisions/core/BasicGraphEdge.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* MIT License
*
* Copyright (c) 2024-2025 Eugene Terekhov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

package ru.ewc.decisions.core;

import java.util.Objects;

/**
* I am a concrete edge in the DecisionGraph that represents a basic relationship.
* I am immutable and connect two nodes with a specific relationship type.
*
* @since 0.9.2
*/
public final class BasicGraphEdge implements GraphEdge {
/**
* The source node of this edge.
*/
private final GraphNode source;

/**
* The target node of this edge.
*/
private final GraphNode target;

/**
* The type of relationship this edge represents.
*/
private final String relationshipType;

/**
* Constructor.
*
* @param source The source node of this edge.
* @param target The target node of this edge.
* @param relationshipType The type of relationship this edge represents.
*/
public BasicGraphEdge(final GraphNode source, final GraphNode target, final String relationshipType) {
this.source = Objects.requireNonNull(source, "Source node cannot be null");
this.target = Objects.requireNonNull(target, "Target node cannot be null");
this.relationshipType = Objects.requireNonNull(relationshipType, "Relationship type cannot be null");
}

@Override
public GraphNode source() {
return this.source;
}

@Override
public GraphNode target() {
return this.target;
}

@Override
public String relationshipType() {
return this.relationshipType;
}

@Override
public String id() {
return String.format("%s--%s-->%s", this.source.id(), this.relationshipType, this.target.id());
}

@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final BasicGraphEdge that = (BasicGraphEdge) obj;
return Objects.equals(this.source, that.source) &&
Objects.equals(this.target, that.target) &&
Objects.equals(this.relationshipType, that.relationshipType);
}

@Override
public int hashCode() {
return Objects.hash(this.source, this.target, this.relationshipType);
}

@Override
public String toString() {
return "BasicGraphEdge{" +
"source=" + this.source.id() +
", target=" + this.target.id() +
", relationshipType='" + this.relationshipType + '\'' +
'}';
}
}
94 changes: 94 additions & 0 deletions src/main/java/ru/ewc/decisions/core/ConditionNode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* MIT License
*
* Copyright (c) 2024-2025 Eugene Terekhov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

package ru.ewc.decisions.core;

import java.util.Objects;
import ru.ewc.decisions.conditions.Condition;

/**
* I am a concrete node in the DecisionGraph that represents a Condition.
* I am immutable and provide a unique identifier based on the condition's properties.
*
* @since 0.9.2
*/
public final class ConditionNode implements GraphNode {
/**
* The condition this node represents.
*/
private final Condition condition;

/**
* The unique identifier for this condition.
*/
private final String identifier;

/**
* Constructor.
*
* @param condition The condition this node represents.
* @param identifier A unique identifier for this condition.
*/
public ConditionNode(final Condition condition, final String identifier) {
this.condition = Objects.requireNonNull(condition, "Condition cannot be null");
this.identifier = Objects.requireNonNull(identifier, "Identifier cannot be null");
}

@Override
public String id() {
return "condition:" + this.identifier;
}

@Override
public String type() {
return "condition";
}

@Override
public Object component() {
return this.condition;
}

@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final ConditionNode that = (ConditionNode) obj;
return Objects.equals(this.identifier, that.identifier);
}

@Override
public int hashCode() {
return Objects.hash(this.identifier);
}

@Override
public String toString() {
return "ConditionNode{" + "identifier='" + this.identifier + '\'' + '}';
}
}
86 changes: 86 additions & 0 deletions src/main/java/ru/ewc/decisions/core/CoordinateNode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* MIT License
*
* Copyright (c) 2024-2025 Eugene Terekhov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

package ru.ewc.decisions.core;

import java.util.Objects;

/**
* I am a concrete node in the DecisionGraph that represents a Coordinate.
* I am immutable and provide a unique identifier based on the coordinate's string representation.
*
* @since 0.9.2
*/
public final class CoordinateNode implements GraphNode {
/**
* The coordinate this node represents.
*/
private final Coordinate coordinate;

/**
* Constructor.
*
* @param coordinate The coordinate this node represents.
*/
public CoordinateNode(final Coordinate coordinate) {
this.coordinate = Objects.requireNonNull(coordinate, "Coordinate cannot be null");
}

@Override
public String id() {
return "coordinate:" + this.coordinate.asString();
}

@Override
public String type() {
return "coordinate";
}

@Override
public Object component() {
return this.coordinate;
}

@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final CoordinateNode that = (CoordinateNode) obj;
return Objects.equals(this.coordinate, that.coordinate);
}

@Override
public int hashCode() {
return Objects.hash(this.coordinate);
}

@Override
public String toString() {
return "CoordinateNode{" + "coordinate=" + this.coordinate.asString() + '}';
}
}
85 changes: 85 additions & 0 deletions src/main/java/ru/ewc/decisions/core/DecisionGraph.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* MIT License
*
* Copyright (c) 2024-2025 Eugene Terekhov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

package ru.ewc.decisions.core;

import java.util.Set;

/**
* I am an immutable graph representation of decision tables and their components.
* My nodes are decision table components like Coordinates, Conditions, Rules, and DecisionTables.
* My edges represent relationships like "part_of", "lhs_of", "rhs_of", and "operator_of".
* I am thread-safe and built once from source files, then cached for reuse.
*
* @since 0.9.2
*/
public interface DecisionGraph {
/**
* Returns all nodes in this graph.
*
* @return An immutable set of all nodes in the graph.
*/
Set<GraphNode> nodes();

/**
* Returns all edges in this graph.
*
* @return An immutable set of all edges in the graph.
*/
Set<GraphEdge> edges();

/**
* Returns all nodes of a specific type.
*
* @param nodeType The class of nodes to return.
* @param <T> The type of nodes to return.
* @return An immutable set of nodes of the specified type.
*/
<T extends GraphNode> Set<T> nodesOfType(Class<T> nodeType);

/**
* Returns all edges of a specific type.
*
* @param edgeType The class of edges to return.
* @param <T> The type of edges to return.
* @return An immutable set of edges of the specified type.
*/
<T extends GraphEdge> Set<T> edgesOfType(Class<T> edgeType);

/**
* Returns all edges that have the specified node as their source.
*
* @param node The source node.
* @return An immutable set of edges originating from the specified node.
*/
Set<GraphEdge> edgesFrom(GraphNode node);

/**
* Returns all edges that have the specified node as their target.
*
* @param node The target node.
* @return An immutable set of edges targeting the specified node.
*/
Set<GraphEdge> edgesTo(GraphNode node);
}
Loading