butterfly icon indicating copy to clipboard operation
butterfly copied to clipboard

Simplify extensions API

Open fabiocarvalho777 opened this issue 6 years ago • 0 comments

Butterfly extensions API should be improved and simplified. A few ideas below.

  1. Remove class com.paypal.butterfly.extensions.api.Extension.
    1. Extension meta-data should be auto-discovered by Butterfly from MANIFEST.MF file
    2. Extension upgrade step chain should be auto-discovered by Butterfly based on Butterfly annotations (more details below)
    3. Transformation template automatic resolution should be moved to its own class, which should implement interface om.paypal.butterfly.extensions.api.TemplateResolution
  2. Introduce a Butterfly extension YAML configuration file called extension.yaml (see example below)
  3. 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 and UpgradeTemplate classes might be removed. An upgrade step then would be defined by implementing TransformationTemplate, 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)

fabiocarvalho777 avatar Jun 13 '18 20:06 fabiocarvalho777