Scaffolding utility for common utility classes


Introduction

OO programming frequently leverages several helper classes such as Enum's, Parameter objects and Exceptions. Developers tend to use those beneficial patterns more frequently when creation of those helping objects is as simple as possible. Due to limitations of different OpenEdge releases a few of those patterns lead to a large amount of repeatedly written code.

We therefore provide a common line interface based (CLI) scaffolding for

  • Enums
  • Serializable Parameter objects
  • Exceptions
  • Generic Lists and Dictionaries
  • Strong-typed Named Queries
  • Value Object Cache

Quick Reference

scl-gen Enum SampleEnum Monday Tuesday Wednesday Thursday Friday Saturday Sunday
scl-gen Parameter SampleParameter Value1 Value2
scl-gen ParameterWithInterface SampleParameter Value1 Value2
scl-gen ParameterWithReadOnlyInterface SampleParameter Value1 Value2
scl-gen Interface SampleInterface Value1 Value2
scl-gen ReadOnlyInterface SampleInterface Value1 Value2
scl-gen ValueObject Date Day:integer Month:integer Year:integer
scl-gen Exception SampleException
scl-gen GenericList ListSample MemberClassName
scl-gen GenericDictionary DictionarySample MemberClassName
scl-gen NamedQuery OrdersInMonthQuery OrdersInMonth Month Year

Property data-types 

When scl-gen command line parameters resemble properties in the generated class, those will be generated by default as CHARACTER. That is not always what you need so you can specify the data-type after the colon per property.

scl-gen Parameter SampleParameter Value1:Integer Value2:int Value3:dec Value4:log Value5


Requirements

The scaffolding utility is implemented using the scl-gen batch script. This batch script is located in the Consultingwerk/Studio/Scaffolding folder of the SmartComponent Library and should be added to the Windows PATH.

The scaffolding utility is further leveraging Apache ANT and PCT. We expect that an ANT installation with PCT.jar in the lib folder is accessible using the Windows PATH as well.

The scaffolding utility needs to make certain assumptions about the development environment. The utility can only be used on the command line from within in a sub folder of a Progress Developer Studio (PDSOE) project. The utility will search the directory tree upwards from the current directory and will fail if no .propath utility (default PDSOE configuration) is found. The .propath file is required to gather information about the Progress Developer Studio project structure.

The utility is partly implemented in ABL - so a Progress runtime must be located. When no DLC environment variable is set, the utility will seek for a supported Progress version in the Windows registry.

Scaffolding

The scaffolding is generally executed using the following command. The parameters for the Template Name and the Class Name are mandatory. The generated classes Package name is determined automatically based on the working directory relatively to the PDSOE's projects's root folder:

scl-gen <Template Name> <Class Name> <Parameter 1> <Parameter 2> <Parameter 3> ....

Enums

The following scaffolding command creates an Enum which can be used as an ABL native Enum (OpenEdge 11.6 ...) or a Consultingwerk Enum (prior to 11.6).

scl-gen Enum SampleEnum Monday Tuesday Wednesday Thursday Friday Saturday Sunday

This creates the class file SampleEnum.cls in the current directory:

/*------------------------------------------------------------------------
    File        : SampleEnum
    Purpose     :
    Syntax      :
    Description :
    Author(s)   : 
    Created     : 06.09.2017 09:52:47
    Notes       :
  ----------------------------------------------------------------------*/

{Consultingwerk/products.i}

&IF DEFINED (NativeEnums) NE 0 &THEN
ENUM Test.SampleEnum:

    DEFINE ENUM Monday Tuesday Wednesday Thursday Friday Saturday Sunday  .
 
END ENUM .

&ELSE
BLOCK-LEVEL ON ERROR UNDO, THROW.

USING Test.*                                    FROM PROPATH .
USING Progress.Lang.*                           FROM PROPATH .

CLASS Test.SampleEnum
    INHERITS Consultingwerk.Enum:

    {Consultingwerk/EnumMember.i Monday 1 SampleEnum}
    {Consultingwerk/EnumMember.i Tuesday 2 SampleEnum}
    {Consultingwerk/EnumMember.i Wednesday 3 SampleEnum}
    {Consultingwerk/EnumMember.i Thursday 4 SampleEnum}
    {Consultingwerk/EnumMember.i Friday 5 SampleEnum}
    {Consultingwerk/EnumMember.i Saturday 6 SampleEnum}
    {Consultingwerk/EnumMember.i Sunday 7 SampleEnum}

    /*------------------------------------------------------------------------------
        Purpose: Constructor for the SampleEnum class
        Notes:
        @param piValue The integer enum value
        @param pcLabel The character enum label
    ------------------------------------------------------------------------------*/
    CONSTRUCTOR PRIVATE SampleEnum (piValue AS INTEGER, pcLabel AS CHARACTER):
        SUPER ().

        ASSIGN THIS-OBJECT:Value = piValue
               THIS-OBJECT:Label = pcLabel .

    END CONSTRUCTOR.

    {Consultingwerk/EnumFromString.i Test.SampleEnum}

END CLASS.
&ENDIF

Serializable Parameter Objects

The following scaffolding command creates an JSON serializable Parameter object .

scl-gen Parameter SampleParameter Value1 Value2

This creates the class file SampleParameter.cls in the current directory:

/*------------------------------------------------------------------------
    File        : SampleParameter
    Purpose     :
    Syntax      :
    Description :
    Author(s)   : 
    Created     : 06.09.2017 09:56:27
    Notes       :
  ----------------------------------------------------------------------*/

BLOCK-LEVEL ON ERROR UNDO, THROW.

{Consultingwerk/products.i}

USING Consultingwerk.*                          FROM PROPATH .
USING Test.*                                    FROM PROPATH .
USING Progress.Lang.*                           FROM PROPATH .

CLASS Test.SampleParameter
    INHERITS JsonSerializable 
    {&SERIALIZABLE}:

    {Consultingwerk/JsonSerializableProperty.i Value1 CHARACTER} .
    {Consultingwerk/JsonSerializableProperty.i Value2 CHARACTER} .

    /*------------------------------------------------------------------------------
        Purpose: Constructor for the SampleParameter class
        Notes:
    ------------------------------------------------------------------------------*/
    CONSTRUCTOR PUBLIC SampleParameter ():
        SUPER ().

    END CONSTRUCTOR.

    /*------------------------------------------------------------------------------
        Purpose: Constructor for the SampleParameter class
        Notes:
        @param pcValue1 The value for the Value1 property   
        @param pcValue2 The value for the Value2 property   
    ------------------------------------------------------------------------------*/
    CONSTRUCTOR PUBLIC SampleParameter (pcValue1 AS CHARACTER, pcValue2 AS CHARACTER):
        SUPER ().

        ASSIGN THIS-OBJECT:Value1 = pcValue1
               THIS-OBJECT:Value2 = pcValue2
                .

    END CONSTRUCTOR.

END CLASS.

Exceptions

The following scaffolding command creates an Exception object .

scl-gen Exception SampleException

This creates the class file SampleException.cls in the current directory:

/*------------------------------------------------------------------------
    File        : SampleException
    Purpose     :
    Syntax      :
    Description :
    Author(s)   :
    Created     : 06.09.2017 09:58:17
    Notes       :
  ----------------------------------------------------------------------*/

BLOCK-LEVEL ON ERROR UNDO, THROW .

{Consultingwerk/products.i}

USING Consultingwerk.*                          FROM PROPATH .
USING Consultingwerk.Exceptions.*               FROM PROPATH .
USING Test.*                                    FROM PROPATH .
USING Progress.Lang.*                           FROM PROPATH .

CLASS Test.SampleException
    INHERITS Exception
    {&SERIALIZABLE}:

    /**
     * Purpose: Constructor of the SampleException class
     * Notes:
     */
    CONSTRUCTOR PUBLIC SampleException ():

        SUPER ().

    END CONSTRUCTOR.

    /**
     * Purpose: Constructor of the SampleException class
     * Notes:
     * @param pcErrorString The error message associated with this Exception object
     * @param piMessageNumber The error message number associated with this Exception object
     */
    CONSTRUCTOR PUBLIC SampleException (pcErrorString AS CHARACTER,
                                        piMessageNumber AS INTEGER):

        SUPER (pcErrorString, piMessageNumber).

    END CONSTRUCTOR.

    /**
     * Purpose: Constructor of the SampleException class
     * Notes:
     * @param pcErrorString The error message associated with this Exception object
     */
    CONSTRUCTOR PUBLIC SampleException (pcErrorString AS CHARACTER):

        SUPER (pcErrorString).

    END CONSTRUCTOR.

    /**
     * Purpose: Constructor of the SampleException class
     * Notes:
     * @param poInnerException The reference to the original error
     */
    CONSTRUCTOR PUBLIC SampleException (poInnerException AS Error):

        SUPER (poInnerException).

    END CONSTRUCTOR.

    /**
     * Purpose: Constructor of the SampleException class
     * Notes:
     * @param poInnerException The reference to the original error
     * @param pcErrorString The error message associated with this Exception object
     * @param piMessageNumber The error message number associated with this Exception object
     */
    CONSTRUCTOR PUBLIC SampleException (poInnerException AS Error,
                                        pcErrorString AS CHARACTER,
                                        piMessageNumber AS INTEGER):

        SUPER (poInnerException, pcErrorString, piMessageNumber).

    END CONSTRUCTOR.

    /**
     * Purpose: Constructor of the SampleException class
     * Notes:
     * @param poInnerException The reference to the original error
     * @param pcErrorString The error message associated with this Exception object
     */
    CONSTRUCTOR PUBLIC SampleException (poInnerException AS Error,
                                        pcErrorString AS CHARACTER):

        SUPER (poInnerException, pcErrorString).

    END CONSTRUCTOR.

END CLASS.

GenericList

The following scaffolding command creates an GenericList object for the given MemberClassName. The Add method is provided as a sample for custom add methods. This can be changed to fit or removed.

scl-gen GenericList ListSample MemberClassName

This creates the class file SampleException.cls in the current directory:

/*------------------------------------------------------------------------
    File        : ListSample
    Purpose     :
    Syntax      :
    Description :
    Author(s)   : 
    Created     : 08.09.2017 06:36:37
    Notes       :
  ----------------------------------------------------------------------*/

BLOCK-LEVEL ON ERROR UNDO, THROW.

USING Consultingwerk.Framework.Base.*           FROM PROPATH .
USING Test.*                                    FROM PROPATH .
USING Progress.Lang.*                           FROM PROPATH .

{Consultingwerk/products.i}

CLASS Test.ListSample
    INHERITS GenericList:

    {Consultingwerk/Framework/Base/GenericList.i MemberClassName}

/*
    /*------------------------------------------------------------------------------
        Purpose: Adds an Item to this List
        Notes:
        @param pcValue1 
        @param pcValue2
        @param pcValue3
        @return The Item that was created
    ------------------------------------------------------------------------------*/
    METHOD PUBLIC MemberClassName Add (pcValue1 AS CHARACTER,
                                       pcValue2 AS CHARACTER,
                                       pcValue3 AS CHARACTER):

        DEFINE VARIABLE oItem AS Column NO-UNDO .

        oColumn = NEW Column () .

        ASSIGN oItem:Value1 = pcValue1
               oItem:Value2 = pcValue2
               oItem:Value3 = pcValue3 .

        RETURN THIS-OBJECT:Add (oItem) .

    END METHOD .
*/

END CLASS.

GenericDictionary

The following scaffolding command creates an GenericList object for the given MemberClassName. 

scl-gen GenericDictionary DictionarySample MemberClassName

This creates the class file SampleException.cls in the current directory:

/*------------------------------------------------------------------------
    File        : DictionarySample
    Purpose     :
    Syntax      :
    Description :
    Author(s)   : 
    Created     : 08.09.2017 06:43:15
    Notes       :
  ----------------------------------------------------------------------*/

BLOCK-LEVEL ON ERROR UNDO, THROW.

USING Consultingwerk.Framework.Base.*           FROM PROPATH .
USING Test.*                                    FROM PROPATH .
USING Progress.Lang.*                           FROM PROPATH .

{Consultingwerk/products.i}

CLASS Test.DictionarySample
    INHERITS GenericDictionary:

    {Consultingwerk/Framework/Base/GenericDictionary.i MemberClassName}

END CLASS.

Strong-typed Named Queries

The following command creates a strong-typed Named Query Parameter class.

scl-gen NamedQuery OrdersInMonthQuery OrdersInMonth Month Year

This creates the class file OrdersInMonthQuery.cls in the current directory:

/*------------------------------------------------------------------------
    File        : OrdersInMonthQuery
    Purpose     :
    Syntax      :
    Description :
    Author(s)   : 
    Created     : 27.09.2017 21:29:10
    Notes       :
  ----------------------------------------------------------------------*/

USING Consultingwerk.OERA.* FROM PROPATH .

{Consultingwerk/products.i}

CLASS Test.OrdersInMonthQuery
    INHERITS NamedQueryParameter:

    /*------------------------------------------------------------------------------
        Purpose: Constructor for the OrdersInMonthQuery class
        Notes:
        @param pcMonth The Month query parameter
        @param pcYear The Year query parameter
    ------------------------------------------------------------------------------*/
    CONSTRUCTOR PUBLIC OrdersInMonthQuery (pcMonth AS CHARACTER,
                                           pcYear AS CHARACTER):
        SUPER ("OrdersInMonth":U).

        THIS-OBJECT:Parameters:Add ("Month":U, pcMonth) .
        THIS-OBJECT:Parameters:Add ("Year":U, pcYear) .

    END CONSTRUCTOR.

END CLASS.

Value Object

The following scaffolding command creates an immutable value object.

scl-gen ValueObject WeightValueObject Weight:decimal Unit

This creates the class file WeightValueObject.cls in the current directory:

/*------------------------------------------------------------------------
    File        : WeightValueObject
    Purpose     :
    Syntax      :
    Description :
    Author(s)   : 
    Created     : 28.05.2019 06:53:57
    Notes       :
  ----------------------------------------------------------------------*/

BLOCK-LEVEL ON ERROR UNDO, THROW.

{Consultingwerk/products.i}

USING Consultingwerk.*                          FROM PROPATH .
USING Test.*                                    FROM PROPATH .
USING Progress.Lang.*                           FROM PROPATH .

CLASS Test.WeightValueObject
    INHERITS ValueObject:

    /**
     * Purpose: Returns the Weight value
     * Notes:
     */
    DEFINE PUBLIC PROPERTY Weight AS DECIMAL NO-UNDO 
    GET.
    PRIVATE SET.    

    /**
     * Purpose: Returns the Unit value
     * Notes:
     */
    DEFINE PUBLIC PROPERTY Unit AS CHARACTER NO-UNDO 
    GET.
    PRIVATE SET.    

    /**
     * Purpose: Constructor for the WeightValueObject class
     * Notes:
     * @param pWeight The value for the Weight property   
     * @param pUnit The value for the Unit property   
     */
    CONSTRUCTOR PUBLIC WeightValueObject (pWeight AS DECIMAL, pUnit AS CHARACTER):

        ASSIGN THIS-OBJECT:Weight = pWeight
               THIS-OBJECT:Unit = pUnit
                .

    END CONSTRUCTOR.

END CLASS.

Value Object Cache

The following scaffolding command creates a cache for value objects.

scl-gen ValueObjectCache CharacterHolderCache Consultingwerk.CharacterHolder

This creates the class file CharacterHolderCache.cls in the current directory:

/*------------------------------------------------------------------------
    File        : CharacterHolderCache
    Purpose     :
    Syntax      :
    Description :
    Author(s)   : 
    Created     : 27.12.2018 23:58:01
    Notes       :
  ----------------------------------------------------------------------*/

BLOCK-LEVEL ON ERROR UNDO, THROW.

USING Consultingwerk.Framework.Base.*           FROM PROPATH .
USING Test.*                                    FROM PROPATH .
USING Progress.Lang.*                           FROM PROPATH .

{Consultingwerk/products.i}

CLASS Test.CharacterHolderCache
    INHERITS ValueObjectCacheBase:

    {Consultingwerk/Framework/Base/GenericValueObjectCache.i CharacterHolderCache Consultingwerk.CharacterHolder}

END CLASS.


Accessing the command line interface (CLI) from within Progress Developer Studio

This discussion on Stack Overflow describes a couple of approaches which allow a developer to access CLI tools from within Progress Developer Studio. Here's our preferred one.

Create an External Tools Configuration with the followinig settings:

SettingValue
NameCLI Console
Location${env_var:ComSpec}
Working Directory${resource_loc}
Allocate ConsoleChecked
Launch in BackgroundChecked

This configuration should be used in the following way: 

  1. Select a folder in the "Project Explorer" view
  2. Execute the "CLI Console" custom tool configuration

This will launch a console window with the selected folder as the working directory. 

Now you can execute the scl-gen tools from the Console view: