butterfly
butterfly copied to clipboard
Simplify extensions API
Butterfly extensions API should be improved and simplified. A few ideas below.
- Remove class
com.paypal.butterfly.extensions.api.Extension
.- Extension meta-data should be auto-discovered by Butterfly from MANIFEST.MF file
- Extension upgrade step chain should be auto-discovered by Butterfly based on Butterfly annotations (more details below)
- Transformation template automatic resolution should be moved to its own class, which should implement interface
om.paypal.butterfly.extensions.api.TemplateResolution
- Introduce a Butterfly extension YAML configuration file called
extension.yaml
(see example below) - Transformation definition phases are specified programmatically using the annotations (see below).
Configuration file
This file should be named extension.yaml
and be present in the extension jar class-path. Its content can be defined based on the sample below.
#######################
# optional properties #
#######################
# Application meta-data. This is usually auto-discovered by Butterfly
# based on the jar MANIFEST.MF file. However, extension developers might
# set it here explicitly if preferred, as seen below.
#
# name: my-extension
# version: 1.0.0
# description: My extension
# Butterfly 3 automatically scans and registers transformation templates.
# It also automatically sets upgrade steps chain (if upgrade templates are present), based on the @Version annotation.
# However, automatic upgrade step chaining only works if the application used semantic versioning. If not, the upgrade chain
# can be set manually, as seen below.
#
# upgrade:
# step:
# - 1.5.2-red
# - 1.5.2-green
# - 1.5.2-black
#######################
# mandatory properties
#######################
# Packages to be scanned by Butterfly to register transformation templates,
# auto-resolution classes, etc
scan-packages:
- com.myextension.foo
- com.myextension.bar
Transformation definition interfaces
/**
* Butterfly might be able to automatically identify, based on the application
* content, the most applicable transformation template to be used.
*/
@FunctionalInterface
public interface TemplateResolution {
/**
* Butterfly might be able to automatically identify, based on the application
* content, the most applicable transformation template to be used.
* If no template applies to the application content, a {@link TemplateResolutionException}
* is thrown explaining the reason why no template could be chosen.
*
* @param applicationFolder the folder where the code of the application to be transformed is
* @return the chosen transformation template
* @throws TemplateResolutionException if no template applies
*/
Class<? extends TransformationTemplate> automaticResolution(File applicationFolder) throws TemplateResolutionException;
}
In addition to that:
-
TransformationTemplate
abstract class should be revisited, and probably converted to a functional interface. -
UpgradeStep
andUpgradeTemplate
classes might be removed. An upgrade step then would be defined by implementingTransformationTemplate
, but annotating it with@UpgradeStep
.
Sample transformation template
public class MyTransform implements TransformationTemplate {
// There can be only one Transform annotated method for a given type in a class
@Transform
public void transform() {
// Common transform
}
@Transform(type = "Messaging")
public void upgradeMessaging() {
// Messaging specific transform
}
@Transform(type = "REST")
public void upgradeRest() {
// REST specific transform
}
// There can be only one PostTransform annotated method for a given type in a class
@PostTransform
public void postTransform() {
// Post-transfrom transforms
}
@PostTransform(type = "Messaging")
public void postTransformMessaging() {
// Post-transfrom transforms for Messaging applications
}
// There can be only one Validate annotated method for a given type in a class
// Order is not deterministic for the ones on same phase
// Throws a validation exception (type to be defined) if it fails
@Validate
public void validation() throws Exception {
// Validation utilities post transformation
}
@Validate(phase = "pre", type = "REST")
public void preValidationRest() throws Exception {
// Validation utilities pre transformation for REST applications
}
}
Sample upgrade step
@UpgradeStep(version = "2.1.9")
public class UpgradeStep_2_1_8_to_2_1_9 implements TransformationTemplate {
// There can be only one Upgrade annotated method for a given type in a class
@Upgrade
public void upgrade() {
// Common transforms
}
@Upgrade(type = "Messaging")
public void upgradeMessaging() {
// Messaging specific transforms
}
@Upgrade(type = "REST")
public void upgradeRest() {
// REST specific transforms
}
// There can be only one PostUpgrade annotated method for a given type in a class
@PostUpgrade
public void postUpgrade() {
// Post-upgrade transforms
}
@PostTransform(type = "Messaging")
public void postUpgradeMessaging() {
// Post-transform transforms for Messaging applications
}
// There can be only one Validate annotated method for a given type in a class
// Order is not deterministic for the ones on same phase
// Throws a validation exception (type to be defined) if it fails
@Validate(phase = "pre")
public void preValidation() throws Exception {
// Validation utilities pre transformation
}
@Validate(phase = "postStep", type = "REST")
public void postStepValidationRest() throws Exception {
// Validation utilities for REST post upgrade step
}
}
Execution order
Transformation
*@Validation(pre, type) -> @Transform -> *@Transform(type) -> *@PostTransform(type) -> *@Validation(post, type)
Upgrade
*@Validation(pre, type) -> *{ @Validation(preStep, type) -> @Upgrade -> *@Upgrade(type) -> *@PostUpgrade(type) -> *@Validation(postStep, type) } -> *@Validation(post, type)
Transformation definition annotations
Annotation | Target | Description |
---|---|---|
@Transform |
method | Mark a method, under an implementation of TransformationTemplate , that contains transformation definition (utilities and operations) |
@PostTransform |
method | Mark one method in a @Transform annotated type to be called right after all @Transform annotated methods are executed. The post transform method may add utilities and or operations that must be executed necessarily after transform utilities and operations defined via @Transform methods are performed |
@UpgradeStep |
type | Mark a class or interface as an upgrade step, having one or more @Upgrade annotated methods, which should contain upgrade step definition (utilities and operations) |
@Upgrade |
method | Mark a method, under a @UpgradeStep annotated type, that contains upgrade step definition (utilities and operations) |
@PostUpgrade |
method | Mark one method in a @Upgrade annotated type to be called right after all @Upgrade annotated methods are executed. The post upgrade method may add utilities and or operations that must be executed necessarily after upgrade utilities and operations defined via @Upgrade methods are performed |
@Validate |
method | Mark one or more methods to be called before or after transformation methods (@Transform , @Upgrade , @PostTransform or @PostUpgrade ) to evaluate if the application is in a valid state. They can be configured to run in four different phases, pre or post transformation, and pre or post upgrade |
Annotation properties
Annotation | Property | Possible values | Default Value | Mandatory | Description |
---|---|---|---|---|---|
@Transform |
type |
String |
null |
no | Classify a transform to be applied to a particular pre-defined application type |
@PostTransform |
type |
String |
null |
no | Classify a transform to be applied to a particular pre-defined application type |
@UpgradeStep |
version |
String |
null |
yes | Specify a particular upgrade step version |
@Upgrade |
type |
String |
null |
no | Classify a transform to be applied to a particular pre-defined application type |
@PostUpgrade |
type |
String |
null |
no | Classify a transform to be applied to a particular pre-defined application type |
@Validate |
type |
String |
null |
no | Classify a transform to be applied to a particular pre-defined application type |
@Validate |
phase |
pre , post , preStep , postStep |
post |
no | Specify when the validation should be run. Possible values are before transformation begins (pre ), after it ended (post ), or in between upgrade steps (preStep and postStep ) |