Skip to main content

The POJO-actor Journey: From v1.0.0 to v2.12.0

· 6 min read
Scivics Lab
Development Team

A retrospective on the evolution of POJO-actor, the lightweight actor model library for Java. This post covers the major milestones from the initial release (v1.0.0) through v2.12.0.

What is POJO-actor?

POJO-actor is a lightweight actor model library that turns any Plain Old Java Object into a concurrent actor. Key design principles:

  • Zero dependencies: No base classes to extend, no interfaces to implement
  • Virtual Thread native: Built for Java 21+, each actor runs on its own virtual thread
  • GraalVM compatible: No reflection in core features
  • Workflow engine: YAML/JSON/XML-based workflow definitions
  • Distributed support: Multi-node actor communication via lightweight HTTP

v1.0.0 (October 12, 2025) - The Beginning

The first release established the core actor model.

Core Components

  • ActorSystem: Manages actor lifecycle and message routing
  • ActorRef: Reference to an actor for message sending
  • Root: The root actor of the system

Basic Messaging

// Create an actor from any POJO
IIActorRef<MyService> actor =
new IIActorRef<>("service", new MyService(), system);

// Asynchronous messaging
actor.tell(s -> s.process("data"));

// Synchronous request-response
String result = actor.ask(s -> s.compute(42)).get();

Tests: Basic test suite implemented


v1.1.0 (October 12, 2025) - Immediate Execution

Added bypass methods for urgent operations.

tellNow / askNow

// Bypass the message queue for urgent operations
actor.tellNow(s -> s.emergencyStop());
String result = actor.askNow(s -> s.getStatus());

These methods execute immediately without waiting in the message queue—useful for time-critical operations.

Tests: 17 tests (including 6 new tests for tellNow/askNow)


v2.0.0 (October 12, 2025) - Workflow Engine Integration

A major release that integrated the workflow engine and dynamic actor loading.

Workflow Engine

YAML/JSON-based workflow definitions for data-driven actor coordination:

name: my-workflow
steps:
- states: ["0", "1"]
actions:
- actor: processor
method: initialize

- states: ["1", "2"]
actions:
- actor: processor
method: process
arguments: ["data"]

Dynamic Actor Loading

  • CallableByActionName: String-based actor invocation interface
  • DynamicActorLoader: ServiceLoader pattern for runtime actor loading
  • ActorProvider: Plugin implementation interface

Plugin Architecture

// Implement ActorProvider for plugin discovery
public class MyActorProvider implements ActorProvider {
@Override
public String getName() { return "myActor"; }

@Override
public Object createActor() { return new MyActor(); }
}

Tests: 35 tests


v2.5.0 (October 12, 2025) - Distributed Actors & Scheduler

A major feature release adding distributed capabilities.

Sub-Workflow Patterns

// Pattern A: New interpreter per call
SubWorkflowCaller caller = new SubWorkflowCaller(system);
caller.call("sub-workflow.yaml");

// Pattern B: Reusable interpreter
ReusableSubWorkflowCaller reusable = new ReusableSubWorkflowCaller(system);
reusable.call("sub-workflow.yaml");
reusable.reset(); // Reset for reuse

Scheduler

// Schedule periodic tasks
Scheduler scheduler = new Scheduler(system);
scheduler.scheduleAtFixedRate(
() -> actor.tell(a -> a.healthCheck()),
0, 30, TimeUnit.SECONDS
);

Distributed Actor System

Multi-node actor communication using lightweight HTTP:

// Start distributed system
DistributedActorSystem distributed =
DistributedActorSystem.create("node1", 8080);

// Get remote actor reference
RemoteActorRef remote = distributed.getRemoteActor(
"node2:8080", "processor"
);

// Transparent remote messaging
remote.tell("process", "data");

Features:

  • Automatic node discovery
  • JSON-based string protocol
  • No Kafka, no middleware dependencies
  • Works on Slurm, Kubernetes, bare metal

Tests: 120 tests (100% pass rate)


v2.6.0 (November 25, 2025) - XML & XSLT Support

XML Workflow Format

<workflow name="deploy">
<step states="0,1">
<action actor="deployer" method="prepare"/>
</step>
<step states="1,2">
<action actor="deployer" method="execute"/>
</step>
</workflow>

XSLT Visualization

Transform workflows to HTML visualizations:

WorkflowXsltTransformer transformer = new WorkflowXsltTransformer();
String html = transformer.toTableView("workflow.xml");
String graph = transformer.toGraphView("workflow.xml");

DynamicActorLoaderActor

A built-in actor for loading plugins from workflows:

# Load actor from JAR at runtime
- actor: loader
method: loadFromJar
arguments: ["/plugins/my-actor.jar", "MyActor", "myActor"]

# Create from ServiceLoader provider
- actor: loader
method: createFromProvider
arguments: ["mathPlugin"]

Tests: 150+ tests


v2.7.0 (December 31, 2025) - Execution Modes

ExecutionMode Selection

// POOL: Work-stealing pool execution (default)
Action action = new Action("actor", "method", args, ExecutionMode.POOL);

// DIRECT: Synchronous execution
Action action = new Action("actor", "method", args, ExecutionMode.DIRECT);

Unified Action Format

Consistent Action object format across YAML, JSON, and XML—enabling type-safe execution with execution mode specification.

Tests: 257 tests


v2.8.0 (January 2, 2026) - Sub-Workflows & Pattern Matching

Sub-Workflow Execution

# Call sub-workflow
- actor: this
method: call
arguments: ["sub-workflow.yaml"]

# Apply action to child actors
- actor: this
method: apply
arguments:
- actor: "Species-*"
method: mutate
arguments: [0.05, 0.02, 0.5]

Actor Name Wildcards

// Find matching actors in system
List<ActorRef> actors = system.findMatchingActors("node-*");

// Patterns supported: *, prefix-*, *-suffix

State Pattern Matching

PatternExampleDescription
Exact"1"Exact state match
Wildcard"*"Any state
Negation"!end"Not this state
OR"1|2|3"Any of these states
Comparison">=5"Numeric comparison
JEXL"jexl:state =~ 'error.*'"Regular expression

Tests: 272 tests


v2.9.0 (January 7, 2026) - YAML Overlay

Kustomize-style workflow customization:

# base.yaml
name: deploy-workflow
steps:
- states: ["0", "1"]
actions:
- actor: deployer
method: deploy
arguments: ["app-v1.0"]

# production-overlay.yaml
patches:
- target: steps[0].actions[0].arguments
value: ["app-v1.0-prod"]

PatchEntry Class

Apply partial modifications to base workflows for environment-specific customization (dev/staging/production).

Tests: 280+ tests


v2.10.0 (January 10, 2026) - JSON State API

XPath-style state access for hierarchical data:

// Set nested state
actor.setState("/config/timeout", 30);
actor.setState("/config/retry/max", 3);

// Get state values
int timeout = actor.getState("/config/timeout");

This enables intuitive access to complex state structures within workflows.

Tests: 290+ tests


v2.11.0 (January 11, 2026) - Maven Central

Stable release published to Maven Central:

<dependency>
<groupId>com.scivicslab</groupId>
<artifactId>pojo-actor</artifactId>
<version>2.11.0</version>
</dependency>

Published artifacts:

  • Main JAR
  • Javadoc JAR
  • Sources JAR

Tests: 290+ tests


v2.12.0 (January 18, 2026) - Terminology Refresh

Renamed Concepts

OldNewReason
VertexTransitionBetter represents state transitions
ControllableWorkStealingPoolManagedThreadPoolHides implementation details

ROOT Actor Pattern

Clarified actor hierarchy with the root actor as the starting point for plugin integration.

Workflow Definition Flexibility

# Both keys now supported
steps: # Preferred
transitions: # Also valid

# Documentation support
- states: ["0", "1"]
note: "Initialize the system" # New property
actions:
- actor: init
method: setup

Tests: 300+ tests


Evolution Summary

Feature Timeline

VersionDateKey FeaturesTests
v1.0.02025-10-12Basic actor model, Javadoc-
v1.1.02025-10-12tellNow/askNow immediate execution17
v2.0.02025-10-12Workflow engine, dynamic loading35
v2.5.02025-10-12Distributed actors, scheduler120
v2.6.02025-11-25XML/XSLT, DynamicActorLoaderActor150+
v2.7.02025-12-31ExecutionMode, unified format257
v2.8.02026-01-02Sub-workflows, state patterns272
v2.9.02026-01-07YAML overlay (Kustomize-style)280+
v2.10.02026-01-10JSON State API (XPath-style)290+
v2.11.02026-01-11Maven Central publication290+
v2.12.02026-01-18Transition, ManagedThreadPool, ROOT300+

Core Architectural Principles

  1. Lightweight: Minimal external dependencies
  2. GraalVM Native Image compatible: No reflection in core features
  3. Virtual Threads: Each actor runs on its own virtual thread
  4. POJO-centric: Use existing Java objects as actors
  5. Incremental adoption: Gradually introduce into existing codebases

What's Next?

Check out POJO-actor v2.13.0 for the latest features including JSON State variable expansion fixes, Java plugin support, and the CallableByActionName interface.

References