{"id":13694745,"url":"https://github.com/stateless4j/stateless4j","last_synced_at":"2025-05-03T04:30:53.007Z","repository":{"id":15696113,"uuid":"18433903","full_name":"stateless4j/stateless4j","owner":"stateless4j","description":"Lightweight Java State Machine","archived":false,"fork":false,"pushed_at":"2023-06-17T01:34:38.000Z","size":275,"stargazers_count":897,"open_issues_count":11,"forks_count":190,"subscribers_count":41,"default_branch":"master","last_synced_at":"2024-11-12T21:39:12.563Z","etag":null,"topics":["automata","finite-state-machine","fsm","fsm-library","hierarchical-states","java","state-machines","transition"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stateless4j.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2014-04-04T09:21:52.000Z","updated_at":"2024-11-11T17:56:28.000Z","dependencies_parsed_at":"2024-01-17T07:03:55.968Z","dependency_job_id":"1fa2cc0e-225e-4a97-b223-c96f0786eb0a","html_url":"https://github.com/stateless4j/stateless4j","commit_stats":null,"previous_names":["oxo42/stateless4j"],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stateless4j%2Fstateless4j","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stateless4j%2Fstateless4j/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stateless4j%2Fstateless4j/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stateless4j%2Fstateless4j/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stateless4j","download_url":"https://codeload.github.com/stateless4j/stateless4j/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252144459,"owners_count":21701416,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automata","finite-state-machine","fsm","fsm-library","hierarchical-states","java","state-machines","transition"],"created_at":"2024-08-02T17:01:39.821Z","updated_at":"2025-05-03T04:30:51.244Z","avatar_url":"https://github.com/stateless4j.png","language":"Java","funding_links":[],"categories":["Java","\u003ca name=\"Java\"\u003e\u003c/a\u003eJava","Libraries"],"sub_categories":["Java"],"readme":"Maven\n=====\n```xml\n    \u003cdependency\u003e\n        \u003cgroupId\u003ecom.github.stateless4j\u003c/groupId\u003e\n        \u003cartifactId\u003estateless4j\u003c/artifactId\u003e\n        \u003cversion\u003e2.6.0\u003c/version\u003e\n    \u003c/dependency\u003e\n```\n\nIntroduction\n============\nCreate **state machines** and lightweight state machine-based workflows **directly in java code**.\n\n```java\nStateMachineConfig\u003cState, Trigger\u003e phoneCallConfig = new StateMachineConfig\u003c\u003e();\n\nphoneCallConfig.configure(State.OffHook)\n        .permit(Trigger.CallDialed, State.Ringing);\n\nphoneCallConfig.configure(State.Ringing)\n        .permit(Trigger.HungUp, State.OffHook)\n        .permit(Trigger.CallConnected, State.Connected);\n\n// this example uses Java 8 method references\n// a Java 7 example is provided in /examples\nphoneCallConfig.configure(State.Connected)\n        .onEntry(this::startCallTimer)\n        .onExit(this::stopCallTimer)\n        .permit(Trigger.LeftMessage, State.OffHook)\n        .permit(Trigger.HungUp, State.OffHook)\n        .permit(Trigger.PlacedOnHold, State.OnHold);\n\n// ...\n\nStateMachine\u003cState, Trigger\u003e phoneCall =\n        new StateMachine\u003c\u003e(State.OffHook, phoneCallConfig);\n\nphoneCall.fire(Trigger.CallDialed);\nassertEquals(State.Ringing, phoneCall.getState());\n```\n\nstateless4j is a port of [stateless](https://github.com/nblumhardt/stateless) for java\n\n\nFeatures\n========\nMost standard state machine constructs are supported:\n\n* Generic support for states and triggers of any java type (numbers, strings, enums, etc.)\n* Hierarchical states\n* Entry/exit events for states\n* Guard clauses to support conditional transitions\n* User-defined actions can be executed when transitioning\n* Internal transitions (not calling `onExit`/`onEntry`)\n* Introspection\n\n\nSome useful extensions are also provided:\n* Parameterised triggers\n* Reentrant states\n\nParallel states are not supported, but if you are looking for it, there is a fork that supports it: [ParallelStateless4j](https://gitlab.com/erasmusmc-public-health/parallelstateless4j/).\n\n\nHierarchical States\n===================\nIn the example below, the `OnHold` state is a substate of the `Connected` state. This means that an `OnHold` call is\nstill connected.\n\n```java\nphoneCall.configure(State.OnHold)\n    .substateOf(State.Connected)\n    .permit(Trigger.TakenOffHold, State.Connected)\n    .permit(Trigger.HungUp, State.OffHook)\n    .permit(Trigger.PhoneHurledAgainstWall, State.PhoneDestroyed);\n```\n\nIn addition to the `StateMachine.getState()` property, which will report the precise current state, an `isInState(State)`\nmethod is provided. `isInState(State)` will take substates into account, so that if the example above was in the\n`OnHold` state, `isInState(State.Connected)` would also evaluate to `true`.\n\nEntry/Exit Events\n=================\nIn the example, the `startCallTimer()` method will be executed when a call is connected. The `stopCallTimer()` will be\nexecuted when call completes (by either hanging up or hurling the phone against the wall.)\n\nThe call can move between the `Connected` and `OnHold` states without the `startCallTimer(`) and `stopCallTimer()`\nmethods being called repeatedly because the `OnHold` state is a substate of the `Connected` state.\n\nEntry/Exit event handlers can be supplied with a parameter of type `Transition` that describes the trigger,\nsource and destination states.\n\nAction on transition\n===================\nIt is possible to execute a user-defined action when doing a transition.\nFor a 'normal' or 're-entrant' transition this action will be called\nwithout any parameters. For 'dynamic' transitions (those who compute the\ntarget state based on trigger-given parameters) the parameters of the\ntrigger will be given to the action.\n\nThis action is only executed if the transition is actually taken; so if\nthe transition is guarded and the guard forbids a transition, then the\naction is not executed.\n\nIf the transition is taken, the action will be executed between the\n`onExit` handler of the current state and the `onEntry` handler of the\ntarget state (which might be the same state in case of a re-entrant\ntransition.\n\nLicense\n=======\nApache 2.0 License\n\nCreated by [@oxo42](https://github.com/oxo42)\n\nMaintained by Chris Narkiewicz [@ezaquarii](https://github.com/ezaquarii)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstateless4j%2Fstateless4j","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstateless4j%2Fstateless4j","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstateless4j%2Fstateless4j/lists"}