Skip to content
7 changes: 6 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -296,9 +296,14 @@ Templates are **reusable, declarative change definitions** that enable "no-code
- `ROLLBACK_FIELD` - Payload type for the rollback operation

**Base Class**: `AbstractChangeTemplate` resolves generic types via reflection and provides:
- Field management: `changeId`, `isTransactional`, `configuration`, `applyPayload`, `rollbackPayload`
- Field management: `changeId`, `isTransactional`, `configuration`
- Generic type resolution for APPLY and ROLLBACK payload classes
- Reflective class collection for GraalVM native image support

**Specialized Classes**:
- `AbstractSimpleTemplate`: For single-step changes with `setStep()`/`getStep()`
- `AbstractSteppableTemplate`: For multi-step changes with `setSteps()`/`getSteps()`

**Key Files**:
- `core/flamingock-core-api/src/main/java/io/flamingock/api/template/ChangeTemplate.java`
- `core/flamingock-core-api/src/main/java/io/flamingock/api/template/AbstractChangeTemplate.java`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,21 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;


/**
* Abstract base class for change templates providing common functionality.
*
* <p>This class handles generic type resolution and provides the common fields
* needed by all templates: changeId, isTransactional, and configuration.
*
* <p>For new templates, extend one of the specialized abstract classes:
* <ul>
* <li>{@link AbstractSimpleTemplate} - for templates with a single apply/rollback step</li>
* <li>{@link AbstractSteppableTemplate} - for templates with multiple steps</li>
* </ul>
*/
public abstract class AbstractChangeTemplate<SHARED_CONFIGURATION_FIELD, APPLY_FIELD, ROLLBACK_FIELD> implements ChangeTemplate<SHARED_CONFIGURATION_FIELD, APPLY_FIELD, ROLLBACK_FIELD> {

private final Class<SHARED_CONFIGURATION_FIELD> configurationClass;
Expand All @@ -32,18 +43,6 @@ public abstract class AbstractChangeTemplate<SHARED_CONFIGURATION_FIELD, APPLY_F
protected String changeId;
protected boolean isTransactional;
protected SHARED_CONFIGURATION_FIELD configuration;
/**
* @deprecated Use {@link #stepsPayload} instead. Will be removed in a future release.
*/
@Deprecated
protected APPLY_FIELD applyPayload;
/**
* @deprecated Use {@link #stepsPayload} instead. Will be removed in a future release.
*/
@Deprecated
protected ROLLBACK_FIELD rollbackPayload;
protected List<TemplateStep<APPLY_FIELD, ROLLBACK_FIELD>> stepsPayload;


private final Set<Class<?>> reflectiveClasses;

Expand Down Expand Up @@ -94,34 +93,6 @@ public void setConfiguration(SHARED_CONFIGURATION_FIELD configuration) {
this.configuration = configuration;
}

/**
* @deprecated Use {@link #setStepsPayload(List)} instead. Will be removed in a future release.
*/
@Deprecated
@Override
public void setApplyPayload(APPLY_FIELD applyPayload) {
this.applyPayload = applyPayload;
}

/**
* @deprecated Use {@link #setStepsPayload(List)} instead. Will be removed in a future release.
*/
@Deprecated
@Override
public void setRollbackPayload(ROLLBACK_FIELD rollbackPayload) {
this.rollbackPayload = rollbackPayload;
}

@Override
public void setStepsPayload(List<TemplateStep<APPLY_FIELD, ROLLBACK_FIELD>> stepsPayload) {
this.stepsPayload = stepsPayload;
}

@Override
public List<TemplateStep<APPLY_FIELD, ROLLBACK_FIELD>> getStepsPayload() {
return stepsPayload;
}

@Override
public Class<SHARED_CONFIGURATION_FIELD> getConfigurationClass() {
return configurationClass;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* Copyright 2025 Flamingock (https://www.flamingock.io)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.flamingock.api.template;

/**
* Abstract base class for templates with a single apply/rollback step.
*
* <p>Use this class when your template processes a single operation that may have
* an optional rollback. The YAML structure for this template type is:
*
* <pre>{@code
* id: create-users-table
* template: SqlTemplate
* apply: "CREATE TABLE users ..."
* rollback: "DROP TABLE users"
* }</pre>
*
* <p>The framework will automatically create a {@link TemplateStep} from the
* apply/rollback fields in the YAML and inject it via {@link #setStep}.
*
* @param <SHARED_CONFIG> the type of shared configuration
* @param <APPLY> the type of the apply payload
* @param <ROLLBACK> the type of the rollback payload
*/
public abstract class AbstractSimpleTemplate<SHARED_CONFIG, APPLY, ROLLBACK>
extends AbstractChangeTemplate<SHARED_CONFIG, APPLY, ROLLBACK> {

protected TemplateStep<APPLY, ROLLBACK> step;

public AbstractSimpleTemplate(Class<?>... additionalReflectiveClass) {
super(additionalReflectiveClass);
}

/**
* Sets the step containing the apply and optional rollback payloads.
*
* @param step the template step
*/
public void setStep(TemplateStep<APPLY, ROLLBACK> step) {
this.step = step;
}

/**
* Returns the step containing the apply and optional rollback payloads.
*
* @return the template step, or null if not set
*/
public TemplateStep<APPLY, ROLLBACK> getStep() {
return step;
}

/**
* Checks if this template has a step set.
*
* @return true if a step is set
*/
public boolean hasStep() {
return step != null;
}

/**
* Convenience method to get the apply payload from the step.
*
* @return the apply payload, or null if no step is set
*/
public APPLY getApply() {
return step != null ? step.getApply() : null;
}

/**
* Convenience method to get the rollback payload from the step.
*
* @return the rollback payload, or null if no step is set or no rollback defined
*/
public ROLLBACK getRollback() {
return step != null ? step.getRollback() : null;
}

/**
* Checks if this template has a rollback payload defined.
*
* @return true if a step is set and it has a rollback payload
*/
public boolean hasRollback() {
return step != null && step.hasRollback();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Copyright 2025 Flamingock (https://www.flamingock.io)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.flamingock.api.template;

import java.util.List;

/**
* Abstract base class for templates with multiple steps.
*
* <p>Use this class when your template processes multiple operations, each with
* its own apply and optional rollback. The YAML structure for this template type is:
*
* <pre>{@code
* id: create-orders-collection
* template: MongoChangeTemplate
* steps:
* - apply:
* type: createCollection
* collection: orders
* rollback:
* type: dropCollection
* collection: orders
* - apply:
* type: insert
* collection: orders
* parameters:
* documents:
* - orderId: "ORD-001"
* rollback:
* type: delete
* collection: orders
* parameters:
* filter: {}
* }</pre>
*
* <p>The framework will automatically parse the steps from the YAML and inject
* them via {@link #setSteps}.
*
* <p><b>Rollback Behavior:</b>
* <ul>
* <li>When a step fails, all previously successful steps are rolled back in reverse order</li>
* <li>Steps without rollback operations are skipped during rollback</li>
* <li>Rollback errors are logged but don't stop the rollback process</li>
* </ul>
*
* @param <SHARED_CONFIG> the type of shared configuration
* @param <APPLY> the type of the apply payload for each step
* @param <ROLLBACK> the type of the rollback payload for each step
*/
public abstract class AbstractSteppableTemplate<SHARED_CONFIG, APPLY, ROLLBACK>
extends AbstractChangeTemplate<SHARED_CONFIG, APPLY, ROLLBACK> {

protected List<TemplateStep<APPLY, ROLLBACK>> steps;

public AbstractSteppableTemplate(Class<?>... additionalReflectiveClass) {
super(additionalReflectiveClass);
}

/**
* Sets the list of steps to execute.
*
* @param steps the list of template steps
*/
public void setSteps(List<TemplateStep<APPLY, ROLLBACK>> steps) {
this.steps = steps;
}

/**
* Returns the list of steps.
*
* @return the list of template steps, or null if not set
*/
public List<TemplateStep<APPLY, ROLLBACK>> getSteps() {
return steps;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,17 @@
*/
package io.flamingock.api.template;

import java.util.List;

/**
* Interface representing a reusable change template with configuration of type {@code CONFIG}.
*
* <p>This interface is commonly implemented by classes that act as templates for Changes
* where a specific configuration needs to be injected and managed independently.
*
* <p>Templates should extend one of the abstract base classes:
* <ul>
* <li>{@link AbstractSimpleTemplate} - for templates with a single apply/rollback step</li>
* <li>{@link AbstractSteppableTemplate} - for templates with multiple steps</li>
* </ul>
*/
public interface ChangeTemplate<SHARED_CONFIG_FIELD, APPLY_FIELD, ROLLBACK_FIELD> extends ReflectionMetadataProvider {

Expand All @@ -31,26 +35,6 @@ public interface ChangeTemplate<SHARED_CONFIG_FIELD, APPLY_FIELD, ROLLBACK_FIELD

void setConfiguration(SHARED_CONFIG_FIELD configuration);

/**
* @deprecated Use {@link #setStepsPayload(List)} instead. Will be removed in a future release.
*/
@Deprecated
void setApplyPayload(APPLY_FIELD applyPayload);

/**
* @deprecated Use {@link #setStepsPayload(List)} instead. Will be removed in a future release.
*/
@Deprecated
void setRollbackPayload(ROLLBACK_FIELD rollbackPayload);

void setStepsPayload(List<TemplateStep<APPLY_FIELD, ROLLBACK_FIELD>> stepsPayload);

List<TemplateStep<APPLY_FIELD, ROLLBACK_FIELD>> getStepsPayload();

default boolean hasStepsPayload() {
return getStepsPayload() != null && !getStepsPayload().isEmpty();
}

Class<SHARED_CONFIG_FIELD> getConfigurationClass();

Class<APPLY_FIELD> getApplyPayloadClass();
Expand Down
Loading
Loading