77import dev .dbos .transact .execution .DBOSLifecycleListener ;
88import dev .dbos .transact .execution .RegisteredWorkflow ;
99import dev .dbos .transact .execution .RegisteredWorkflowInstance ;
10+ import dev .dbos .transact .workflow .SerializationStrategy ;
1011import dev .dbos .transact .workflow .Workflow ;
1112import dev .dbos .transact .workflow .WorkflowHandle ;
1213
1314import java .lang .reflect .Method ;
1415import java .util .Collection ;
16+ import java .util .Collections ;
1517import java .util .Objects ;
1618import java .util .Optional ;
1719import java .util .function .Consumer ;
3133 */
3234public class DBOSIntegration {
3335
36+ /**
37+ * Callback used during workflow registration to process each discovered workflow method.
38+ * Implementations receive the {@link Workflow} annotation, the target object, the reflective
39+ * {@link Method}, and the optional instance name.
40+ */
3441 @ FunctionalInterface
3542 public interface RegisteredWorkflowConsumer {
3643 void register (Workflow wfTag , Object target , Method method , String instanceName );
3744 }
3845
3946 private final DBOSConfig config ;
47+ private final WorkflowRegistry workflowRegistry ;
4048 private final Supplier <DBOSExecutor > executorSupplier ;
4149 private final Consumer <DBOSLifecycleListener > listenerConsumer ;
42- private final RegisteredWorkflowConsumer workflowConsumer ;
4350
4451 public DBOSIntegration (
4552 @ NonNull DBOSConfig config ,
53+ @ NonNull WorkflowRegistry workflowRegistry ,
4654 @ NonNull Supplier <DBOSExecutor > executorSupplier ,
47- @ NonNull Consumer <DBOSLifecycleListener > lifecycleConsumer ,
48- @ NonNull RegisteredWorkflowConsumer workflowConsumer ) {
55+ @ NonNull Consumer <DBOSLifecycleListener > lifecycleConsumer ) {
4956 this .config = Objects .requireNonNull (config );
57+ this .workflowRegistry = Objects .requireNonNull (workflowRegistry );
5058 this .executorSupplier = Objects .requireNonNull (executorSupplier );
5159 this .listenerConsumer = Objects .requireNonNull (lifecycleConsumer );
52- this .workflowConsumer = Objects .requireNonNull (workflowConsumer );
5360 }
5461
5562 private DBOSExecutor executor (String caller ) {
@@ -61,14 +68,19 @@ private DBOSExecutor executor(String caller) {
6168 return exec ;
6269 }
6370
71+ /**
72+ * Returns the DBOS configuration supplied at construction time.
73+ *
74+ * @return the active {@link DBOSConfig}
75+ */
6476 public DBOSConfig config () {
6577 return this .config ;
6678 }
6779
6880 /**
69- * Register a lifecycle listener that receives callbacks when DBOS is launched or shut down
81+ * Register a lifecycle listener that receives callbacks when DBOS is launched or shut down.
7082 *
71- * @param listener
83+ * @param listener the listener to register; must not be {@code null}
7284 */
7385 public void registerLifecycleListener (@ NonNull DBOSLifecycleListener listener ) {
7486 listenerConsumer .accept (listener );
@@ -84,12 +96,61 @@ public void registerLifecycleListener(@NonNull DBOSLifecycleListener listener) {
8496 * @param instanceName optional instance name for the workflow (can be null)
8597 * @throws IllegalStateException if called after DBOS is launched
8698 */
87- public void registerWorkflow (
99+ public RegisteredWorkflow registerWorkflow (
88100 @ NonNull Workflow wfTag ,
89101 @ NonNull Object target ,
90102 @ NonNull Method method ,
91103 @ Nullable String instanceName ) {
92- workflowConsumer .register (wfTag , target , method , instanceName );
104+
105+ var workflowName = WorkflowRegistry .getWorkflowName (wfTag , method );
106+ var className = WorkflowRegistry .getWorkflowClassName (target );
107+
108+ return registerWorkflow (
109+ workflowName ,
110+ className ,
111+ instanceName ,
112+ target ,
113+ method ,
114+ wfTag .maxRecoveryAttempts (),
115+ wfTag .serializationStrategy ());
116+ }
117+
118+ /**
119+ * Register a workflow method with DBOS using explicit field values rather than deriving them from
120+ * a {@link Workflow} annotation. Prefer {@link #registerWorkflow(Workflow, Object, Method,
121+ * String)} unless you need to supply names or options that differ from the annotation.
122+ *
123+ * @param workflowName logical name of the workflow
124+ * @param className name of the class that declares the workflow method
125+ * @param instanceName optional instance name distinguishing multiple registrations of the same
126+ * class; may be {@code null}
127+ * @param target the object instance on which the method will be invoked
128+ * @param method the workflow {@link Method}
129+ * @param maxRecoveryAttempts maximum number of recovery attempts; {@code null} uses the default
130+ * @param serializationStrategy strategy used to serialize and deserialize workflow arguments and
131+ * return values; {@code null} uses the default
132+ * @throws IllegalStateException if called after DBOS is launched
133+ */
134+ public RegisteredWorkflow registerWorkflow (
135+ @ NonNull String workflowName ,
136+ @ NonNull String className ,
137+ @ Nullable String instanceName ,
138+ @ NonNull Object target ,
139+ @ NonNull Method method ,
140+ @ Nullable Integer maxRecoveryAttempts ,
141+ @ Nullable SerializationStrategy serializationStrategy ) {
142+ if (executorSupplier .get () != null ) {
143+ throw new IllegalStateException ("Cannot register workflow after DBOS is launched" );
144+ }
145+
146+ return workflowRegistry .registerWorkflow (
147+ workflowName ,
148+ className ,
149+ instanceName ,
150+ target ,
151+ method ,
152+ maxRecoveryAttempts ,
153+ serializationStrategy );
93154 }
94155
95156 /**
@@ -137,7 +198,11 @@ public Object runWorkflow(
137198 * @return list of all registered workflow methods
138199 */
139200 public @ NonNull Collection <RegisteredWorkflow > getRegisteredWorkflows () {
140- return executor ("getRegisteredWorkflows" ).getRegisteredWorkflows ();
201+ var executor = executorSupplier .get ();
202+ if (executor != null ) {
203+ return executor .getRegisteredWorkflows ();
204+ }
205+ return Collections .unmodifiableCollection (workflowRegistry .getWorkflowSnapshot ().values ());
141206 }
142207
143208 /**
@@ -146,15 +211,21 @@ public Object runWorkflow(
146211 * @return list of all class instances containing registered workflow methods
147212 */
148213 public @ NonNull Collection <RegisteredWorkflowInstance > getRegisteredWorkflowInstances () {
149- return executor ("getRegisteredWorkflowInstances" ).getRegisteredWorkflowInstances ();
214+ var executor = executorSupplier .get ();
215+ if (executor != null ) {
216+ return executor .getRegisteredWorkflowInstances ();
217+ }
218+ return Collections .unmodifiableCollection (workflowRegistry .getInstanceSnapshot ().values ());
150219 }
151220
152221 /**
153- * Finds a registered workflow by its workflow name, class name, and instance name.
222+ * Finds a registered workflow by its workflow name and class name, using the default (empty)
223+ * instance name. Equivalent to calling {@link #getRegisteredWorkflow(String, String, String)}
224+ * with an empty string.
154225 *
155226 * @param workflowName the name of the workflow
156227 * @param className the name of the class containing the workflow
157- * @return an Optional containing the RegisteredWorkflow if found, otherwise empty
228+ * @return an {@link Optional} containing the {@link RegisteredWorkflow} if found, otherwise empty
158229 */
159230 public Optional <RegisteredWorkflow > getRegisteredWorkflow (
160231 @ NonNull String workflowName , @ NonNull String className ) {
@@ -171,31 +242,38 @@ public Optional<RegisteredWorkflow> getRegisteredWorkflow(
171242 */
172243 public Optional <RegisteredWorkflow > getRegisteredWorkflow (
173244 @ NonNull String workflowName , @ NonNull String className , @ NonNull String instanceName ) {
174- return executor ("getRegisteredWorkflow" )
175- .getRegisteredWorkflow (workflowName , className , instanceName );
245+ var executor = executorSupplier .get ();
246+ if (executor != null ) {
247+ return executor .getRegisteredWorkflow (workflowName , className , instanceName );
248+ }
249+ var fqName = RegisteredWorkflow .fullyQualifiedName (workflowName , className , instanceName );
250+ return Optional .ofNullable (workflowRegistry .getWorkflowSnapshot ().get (fqName ));
176251 }
177252
178253 /**
179- * Get a system database record stored by an external service A unique value is stored per
180- * combination of service, workflowName, and key
254+ * Get a system database record stored by an external service. A unique value is stored per
255+ * combination of service, workflowName, and key.
181256 *
182- * @param service Identity of the service maintaining the record
183- * @param workflowName Fully qualified name of the workflow
184- * @param key Key assigned within the service+workflow
185- * @return Optional containing the value associated with the service+workflow+key combination, or
186- * empty if not found
257+ * @param service identity of the service maintaining the record
258+ * @param workflowName fully qualified name of the workflow
259+ * @param key key assigned within the service+workflow scope
260+ * @return an {@link Optional} containing the value associated with the service+workflow+key
261+ * combination, or empty if not found
262+ * @throws IllegalStateException if DBOS has not been launched
187263 */
188264 public Optional <ExternalState > getExternalState (String service , String workflowName , String key ) {
189265 return executor ("getExternalState" ).getExternalState (service , workflowName , key );
190266 }
191267
192268 /**
193- * Insert or update a system database record stored by an external service A timestamped unique
194- * value is stored per combination of service, workflowName, and key
269+ * Insert or update a system database record stored by an external service. A timestamped unique
270+ * value is stored per combination of service, workflowName, and key.
195271 *
196- * @param state ExternalState containing the service, workflow, key, and value to store
197- * @return Value associated with the service+workflow+key combination, in case the stored value
198- * already had a higher version or timestamp
272+ * @param state the {@link ExternalState} containing the service, workflow, key, and value to
273+ * store
274+ * @return the value associated with the service+workflow+key combination — may differ from the
275+ * supplied value if the existing record already had a higher version or timestamp
276+ * @throws IllegalStateException if DBOS has not been launched
199277 */
200278 public ExternalState upsertExternalState (ExternalState state ) {
201279 return executor ("upsertExternalState" ).upsertExternalState (state );
0 commit comments