Last active
January 25, 2026 11:22
-
-
Save Garciat/9f5a6e2fcf695bfe822710a4567fe557 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // === Library | |
| interface FeatureKey {} | |
| sealed interface LookupResult<S extends State<S, ?, ?>> { | |
| record Found<S extends State<S, ?, ?>>(S state) implements LookupResult<S> {} | |
| record NotFound<S extends State<S, ?, ?>>() implements LookupResult<S> {} | |
| } | |
| interface FeatureStateStore<K extends FeatureKey, S extends State<S, ?, ?>> { | |
| LookupResult<S> getCurrentState(K key); | |
| void persistState(K key, S newState); | |
| } | |
| sealed interface ParseResult<M extends Message<?>> { | |
| record Success<M extends Message<?>>(M message) implements ParseResult<M> {} | |
| record Failure<M extends Message<?>>() implements ParseResult<M> {} | |
| } | |
| interface FeatureMessageParser<I, M extends Message<?>> { | |
| ParseResult<M> parse(I inbound); | |
| } | |
| interface StateSerializer<S extends State<S, ?, ?>> { | |
| JsonValue serializeState(S state); | |
| S deserializeState(JsonValue serializedState); | |
| } | |
| class JacksonStateSerializerFactory { | |
| static <S extends State<S, ?, ?>> StateSerializer<S> create(Class<S> stateClass) { | |
| // Implementation would use Jackson ObjectMapper to serialize/deserialize | |
| return null; // Placeholder | |
| } | |
| } | |
| sealed interface InitializeResult<S extends State<S, ?, ?>> { | |
| record Success<S extends State<S, ?, ?>>(S initialState) implements InitializeResult<S> {} | |
| record Failure<S extends State<S, ?, ?>>() implements InitializeResult<S> {} | |
| } | |
| interface FeatureStateInitializer<S extends State<S, M, ?>, M extends Message<?>> { | |
| InitializeResult<S> initializeState(M message); | |
| } | |
| interface FeatureStateStoreFactory { | |
| <K extends FeatureKey, S extends State<S, M, ?>, M extends Message<?>> | |
| FeatureStateStore<K, S> createStore( | |
| Class<K> featureKey, | |
| StateSerializer<S> serializer, | |
| FeatureStateInitializer<S, M> initializer); | |
| } | |
| interface Message<K extends FeatureKey> { | |
| K key(); | |
| } | |
| interface Result { | |
| default boolean isFailure() { | |
| return getClass().isAnnotationPresent(Failure.class); | |
| } | |
| @Retention(RetentionPolicy.RUNTIME) | |
| @interface Failure {} | |
| } | |
| interface State<S extends State<S, M, R>, M extends Message<?>, R extends Result> { | |
| Reply<S, R> handle(M message); | |
| } | |
| sealed interface Reply<S extends State<S, ?, R>, R extends Result> { | |
| record Next<S extends State<S, ?, R>, R extends Result>(S newState, R result) | |
| implements Reply<S, R> {} | |
| record WrongMessage<S extends State<S, ?, R>, R extends Result>() implements Reply<S, R> {} | |
| static <S extends State<S, ?, R>, R extends Result> Reply<S, R> next(S newState, R result) { | |
| return new Next<>(newState, result); | |
| } | |
| static <S extends State<S, ?, R>, R extends Result> Reply<S, R> wrongMessage() { | |
| return new WrongMessage<>(); | |
| } | |
| } | |
| sealed interface MessageOutcome<R extends Result> { | |
| record Success<R extends Result>(R result) implements MessageOutcome<R> {} | |
| record Unavailable<R extends Result>(Reason reason) implements MessageOutcome<R> { | |
| enum Reason { | |
| NOT_FOUND, | |
| WRONG_MESSAGE | |
| } | |
| } | |
| } | |
| interface FeaturePort<M extends Message<?>, R extends Result> { | |
| MessageOutcome<R> call(M message); | |
| } | |
| class DefaultFeaturePort< | |
| S extends State<S, M, R>, K extends FeatureKey, M extends Message<K>, R extends Result> | |
| implements FeaturePort<M, R> { | |
| private final FeatureStateStore<K, S> store; | |
| DefaultFeaturePort(FeatureStateStore<K, S> store) { | |
| this.store = store; | |
| } | |
| @Override | |
| public MessageOutcome<R> call(M message) { | |
| return switch (store.getCurrentState(message.key())) { | |
| case LookupResult.Found(var state) -> | |
| switch (state.handle(message)) { | |
| case Reply.Next(S newState, R result) -> { | |
| store.persistState(message.key(), newState); | |
| yield new MessageOutcome.Success<>(result); | |
| } | |
| case Reply.WrongMessage() -> new MessageOutcome.Unavailable<>(WRONG_MESSAGE); | |
| }; | |
| case LookupResult.NotFound() -> new MessageOutcome.Unavailable<>(NOT_FOUND); | |
| }; | |
| } | |
| } | |
| interface DefaultFeaturePortFactory { | |
| <S extends State<S, M, R>, K extends FeatureKey, M extends Message<K>, R extends Result> | |
| FeaturePort<M, R> create(FeatureStateStore<K, S> store); | |
| } | |
| // === Use Case | |
| @Configuration | |
| @Import({SomeFeatureMessageParser.class, SomeFeatureStateInitializer.class}) | |
| class SomeFeatureConfig { | |
| @Bean | |
| FeatureStateStore<SomeFeatureKey, SomeFeatureState> someFeatureStateStore( | |
| JacksonStateSerializerFactory serializerFactory, | |
| FeatureStateStoreFactory stateStoreFactory, | |
| SomeFeatureStateInitializer initializer) { | |
| return stateStoreFactory.createStore( | |
| SomeFeatureKey.class, serializerFactory.create(SomeFeatureState.class), initializer); | |
| } | |
| @Bean | |
| FeaturePort<SomeFeatureMessage, SomeFeatureResult> someFeaturePort( | |
| DefaultFeaturePortFactory factory, | |
| FeatureStateStore<SomeFeatureKey, SomeFeatureState> store) { | |
| return factory.create(store); | |
| } | |
| } | |
| record InboundMessage() {} | |
| class InboundMessageHandler { | |
| private FeatureMessageParser<InboundMessage, SomeFeatureMessage> parser; | |
| private FeaturePort<SomeFeatureMessage, SomeFeatureResult> port; | |
| void handle(InboundMessage inbound) { | |
| SomeFeatureMessage message = | |
| switch (parser.parse(inbound)) { | |
| case ParseResult.Success(var m) -> m; | |
| case ParseResult.Failure() -> throw new IllegalArgumentException(); | |
| }; | |
| switch (port.call(message)) { | |
| case MessageOutcome.Success(var result) -> {} | |
| case MessageOutcome.Unavailable(var reason) -> {} | |
| } | |
| } | |
| } | |
| class SomeFeatureMessageParser implements FeatureMessageParser<InboundMessage, SomeFeatureMessage> { | |
| @Override | |
| public ParseResult<SomeFeatureMessage> parse(InboundMessage inbound) { | |
| return new ParseResult.Success<>(new Initialize(new SomeFeatureKey("example"))); | |
| } | |
| } | |
| record SomeFeatureKey(String entityId) implements FeatureKey {} | |
| sealed interface SomeFeatureMessage extends Message<SomeFeatureKey> {} | |
| record Initialize(SomeFeatureKey key) implements SomeFeatureMessage {} | |
| record UpdateData(SomeFeatureKey key, String data) implements SomeFeatureMessage {} | |
| record Finalize(SomeFeatureKey key) implements SomeFeatureMessage {} | |
| sealed interface SomeFeatureResult extends Result {} | |
| record Ok() implements SomeFeatureResult {} | |
| class SomeFeatureStateInitializer | |
| implements FeatureStateInitializer<SomeFeatureState, SomeFeatureMessage> { | |
| @Override | |
| public InitializeResult<SomeFeatureState> initializeState(SomeFeatureMessage message) { | |
| return switch (message) { | |
| case Initialize m -> new InitializeResult.Success<>(new Uninitialized()); | |
| default -> new InitializeResult.Failure<>(); | |
| }; | |
| } | |
| } | |
| sealed interface SomeFeatureState | |
| extends State<SomeFeatureState, SomeFeatureMessage, SomeFeatureResult> { | |
| default Reply<SomeFeatureState, SomeFeatureResult> handle(SomeFeatureMessage message) { | |
| return switch (message) { | |
| case Initialize m -> handle(m); | |
| case UpdateData m -> handle(m); | |
| case Finalize m -> handle(m); | |
| }; | |
| } | |
| default Reply<SomeFeatureState, SomeFeatureResult> handle(Initialize message) { | |
| return Reply.wrongMessage(); | |
| } | |
| default Reply<SomeFeatureState, SomeFeatureResult> handle(UpdateData message) { | |
| return Reply.wrongMessage(); | |
| } | |
| default Reply<SomeFeatureState, SomeFeatureResult> handle(Finalize message) { | |
| return Reply.wrongMessage(); | |
| } | |
| } | |
| record Uninitialized() implements SomeFeatureState { | |
| @Override | |
| public Reply<SomeFeatureState, SomeFeatureResult> handle(Initialize message) { | |
| return Reply.next(new Initialized("Initial data"), new Ok()); | |
| } | |
| } | |
| record Initialized(String data) implements SomeFeatureState { | |
| @Override | |
| public Reply<SomeFeatureState, SomeFeatureResult> handle(UpdateData message) { | |
| return Reply.next(new Initialized(message.data()), new Ok()); | |
| } | |
| @Override | |
| public Reply<SomeFeatureState, SomeFeatureResult> handle(Finalize message) { | |
| return Reply.next(new Finalized(), new Ok()); | |
| } | |
| } | |
| record Finalized() implements SomeFeatureState {} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment