1
0
-1

Hi Unifacers,

In the current IT world driven from integrations could it be of interest to the Uniface world to have a standardized mode to develop and deploy plugins to Uniface apps? IMHO...YES!

I do not remember this specific subject being discussed, but it could be I was not part of the discussion or I have simply forgotten about it!

Pro...? Cons...? Pitfalls...? Tips...? Suggestions...?

Let's argue about it!

Gianni

  1. Gianni Sandigliano

    UNIFACE plugins

    Definition: a uniface plugin could be a full application (launcher, monitor, configurator, ...) or a part of an application (module, library, ...) that can be used together or integrated within a Uniface application. Each plugin is dedicated to a single business or technical object. Base for each plugin should be a microservice architecture, extended with a re-susable presentation layer.  The word "plugin" is used to identify a software that can easily be re-used in any Uniface installation and configuration.

    Perimeter (DRAFT) for a "whatever" plugin:
    - SelfContainedUARname: UP_XXXX_whatever_VVV where:
        - XXXX is a unique identifier of plugin provider
        - whatever is the concept implemented in the plugin
        - VVV is the plugin version
        each plugin provider is responsible to maintain plugin info updated
    - Mission: [short description (max 250 char) defining the plugin interface perimeter]
    - PluginVersion: x.y[.z]
    - UnifaceVersionsSupported: Ux.Uy[, Ux1.Uy1][, Ux2.Uy2]
    - ComponentsNames: XXXX_*
    - GlobalObjects: Each plugin component is connected to its library named XXXX_*
       Objects being part of SYSTEM_LIBRARY should have their names starting with XXXX_*
       $variation and $language MUST be saved and restored from ALL plugin interactions
       Objects being part of USYS variation should have their names starting with XXXX_*
    - Security: None | ???TBD???
    - DBMS: None | XXXX_APPMODEL
    - UserInterface: None | Char | C/S | Web
    - LanguagesSupported: "USA" MUST be supported! Further list of international codes from ISO-639-3
    - ServicesPerimeter: None | Uniface | LAN | Internet
    - PrintingPerimeter: None | Uniface | OtherToBeSpecified
    - DataExchangePerimeter: InLine | LocalFolder | MailBox | OtherToBeSpecified
    - OperationsList: simpleListOfOperationsAvailableWithoutParams but a short description
    - PresentationComponents: simpleListOfPresentationComponents with attribute: Contained | Indipendent and a short description
    - OtherPluginPreRequisites: None | ListOfOtherPlugin(s)ThatMUSTbeAvailable
    - PluginOptionals: None | ListOfOtherOptionalPlugins
    - OtherTechPreRequisites: None | ListOfOtherTechPreRequisites
    - DeliveryMode: OpenSources | UARonly | withSourcesIfRequested
    - TechDocumentation: None | Samples | Included
    - Contact: eMailAddress

    Let's try with an example 
    (thanks to Theo Neskeens providing initial GoogleMap Integration sample):
    - SelfContainedUARname: UP_GSAN_GMAP_100
    - Mission: Interface to Google Map, Services and Presentations
    - Version: 1.0.0
    - UnifaceVersion: 9.7
    - ComponentsNames: GSAN_*
    - GlobalObjects: None
    - Security: None
    - DBMS: None
    - UserInterface: C/S
    - LanguagesSupported: ITA
    - ServicesPerimeter: Internet
    - PrintingPerimeter: Uniface, GSAN_UPDF plugin
    - DataExchangePerimeter: InLine
    - OperationsList:
    GSAN_GMAP_SVC.getDistance() get distance in km between two GeoPoints|Addresses|POIs in an UIL
    GSAN_GMAP_SVC.getPathFromTo() get traveling steps between two GeoPoints|Addresses|POIs in an UIL
    GSAN_GMAP_SVC.getStaticMap() get static map related to a GeoPoint|Address|POI in an UIL
    - PresentationComponents:
    GSAN_GMAP_MAP Contained form showing either static or dynamic maps
    - OtherPluginPreRequisites: None
    - PluginOptionals: GSAN_UPDF: to interactively print map to PDF
    - OtherTechPreRequisites: Google Developer Account must be setup
    - DeliveryMode: UARonly
    - TechDocumentation: Samples
    - Contact: name.surname@domain.ext

    Simpler HowTo:
    - Add reference to UP_GSAN_GMAP_100 UAR file to the [RESOURCES] section of your ASN file
    - Use in your application activate "GSAN_GMAP_SVC".getDistance() with documented parameters to get distance between two addresses.

    Open questions:
    - For the "Security" item, suggestions are still welcome... (smile)
    - Should a list of Uniface plugins available be maintained on uniface.info? If yes, how?

CommentAdd your comment...

3 answers

  1.  
    1
    0
    -1

    Hi Gianni

    About the UAR-Name:

    I would suggest the follwing format

    UP_<ProviderId>_<PackageId>{_<VersionId>}

    So the only things to manage ist the provider id.

    e.g a plugin from UnifAce will be:
    UP_UNIFACE_GRAPHICS.uar
    or
    UP_UNIFACE_GRAPHICS_V201911.uar
    if this is a newer version.

    Your plugins will then be
    UP_GIANNI_SUPERTOOL1.uar
    UP_GIANNI_SUPERTOOL2.uar

    ...

    Ingo

    1. Gianni Sandigliano

      Hi Ingo,

      good point!

      I agree about UAR name, it could be helpful to have them like you proposed.
      Anyhow: the XXXX code is used into naming convention for various objects...is it still working and fully applicable in all cases?

      Question: in your opinion, what about simple user defined functions like:

      FirstCap(string)
      it gives back the string passed as parameter with first letter of each word forced uppercase.

      Should they be usable directly into code like:
         myVar = FirstCap(anotherVar)
      or only through an activate operation of a component like:
         activate "UP_GIANNI_UTILITIES".FirstCap(anotherVar : IN, myVar : OUT)

      The first solution is simpler but it is more difficult to define a naming convention to avoid ANY overlapping. The second solution is less readable but respect the naming convention already defined.

      Gianni

    2. Ingo Stiller

      Hi Gianni

      Naming convention, the mother of all trouble (smile)
      If the name is to short, you will run into duplicate names. If it is to long, it's unreadable.
      Library/projects names could be a first aid.
      But:
      In 9.7 you can't call a function with a "namespace" at the beginning  of  the name
      $1 =GIANNI::FirstCap("hello")
      wouldn't work 
      Didn't check this in UF 10, but should also not working grumble 
      Same for other global objects like menus&co

      The other idea is to use the name mangeling mechanism *)
      $1 = GIANNI@FirstCap@S@S("hello")
      Where the first  @ spearate the "namespace" from the function name
      The second @ spearate the types of the paramters
      And the third @ spearate the types of the return value

      It's "readable" like C++ (mangeled) function names.
      And one have to keep the names short.

      *) not exactly C++ mangeling, but useable to make up such names by hand


      BTW:
      your funtion FirstCap should have a second parameter "para"
      Just in case one would refine the function call.
      All my function in our application does have this extra parameter.
      e.g.
      GF_GET_PARA_STR(<val_lst>,<key_lst>,<def_val>,<nf_val>,<para>) ; returns string
      This function gets a string out of a UIL(UnifaceItemList) by one of the keys in <key_lst>.
      If in the UIL only the ID but no value found, <def_val> will be used.
      If none of the keys found, <nf_val> will returned.
      If in para is the id UPC then the uppercase will be returned.

      With extra this "para" it's very easy to enhance the function without doing a refactoring of the whole code (smile)

      Ingo


    3. Gianni Sandigliano

      Hi Ingo,

      Your proposal to have a further parameter "para" is already in my habits; I call it "mode" but I use it only when I feel it is somehow needed, when the interface to the concept supported it is not fully clear. This is a good example of "defensive programming".

      I feel your suggestions are getting plugin definition simpler and more consistent and I am going to update plugin definition I have published at the beginning of this thread.

      I hope other Unifacers will give more suggestions based on their experience or will decide to agree on this Uniface plugins concept.

      Thanks for your answers.

      Gianni

    CommentAdd your comment...
  2.  
    1
    0
    -1

    Hi Gianni

    We don't have plugins as you mention them.
    But I try to get our application modular

    So all operation should have the same number of parameters.

    params  string v_VAL_IN   :IN      ;UIL: input data
      string v_VAL_OUT :OUT ;UIL: output data
      string v_PARA :INOUT ;UIL: control data
      string $GDA$ :INOUT ;UIL: global data area
    endparams


    UIL = UnifAceItemList
    The $GDA$ parameter is not yet used in our application, it's for the purpose of transfering environment information through the instances if there are (official) no global objects availble like in services. All operations are recursiv called with this $GDA$ without modifing (directly) the content of $GDA$

    Example: "Create a person" (without any error handling&co)

    v_VAL_IN = ""
    putitem/id v_VAL_IN,"PER_NAM1","Meier"
    putitem/id v_VAL_IN,"PER_NAM2","Peter"
    v_PARA = ""
    putitem/id v_PARA,"COMMIT",1 ; The instance should do a commit on it's own
    activate v_inst."PER_CRT"(v_VAL_IN,v_VAL_OUT,v_PARA,$GDA$)
    v_PER_NR= $item("PER_NR",v_VAL_OUT)


    There a few predefined operation (via include)
    One of them is "GENERAL" to do some background things in an instance.
    e.g. get the list of avaible*) operations  in a component like a reflection interface
    *) Only those wich are defined by default ot declared in a defines trigger

    And there is always a component local variable (beside $GDA$) called $INSTANCEPROERTIES$
    This holds properties of an instance wich could used at runtime.
    A few of this properties are generated a compile tim (like the list of operations), some could be set and read at runtime via special globale procedures. To do this "remote" from another instance, there are two simple operations "SET_INSTANCEPROPERTIES" and "GET_INSTANCEPROPERIES"


    This are some operation we will define by default (smile)


    CB ; CallBack-Interface
    EDIT ; Default interactive EDIT
    GDA_GET ; Get and SET $GDA$ from outside
    GDA_SET ;-"-
    GENERAL ; Some general things, addressed by a parameter TOPIC
    INSTANCEPROPERTIES_GET ; GET and SET $INSTANCEPROPERIES$
    INSTANCEPROPERTIES_SET ; -"-
    OP_CPT_INFO ; Get Information about the instance
    OP_GET_CLL_HANDLE ; Get the collection handle of a entity
    OP_GET_OCC_HANDLE ; Get a occournce handle of a entity
    ...
    xxx


    BTW: About INIT and CLEANUP
    Our framework contains an "instance and transaction monitor"
    So (I hope) all newinstance and deleteinstance are running over this "monitor".
    Every time a instance is about to kill, GENERAL will called with the topic "CLEANUP_AHEAD".
    So a instance have the opportunity to save all values in database an do other cleanup things.
    To do is in this way is important as UnifAce sometimes kills dependig instances at the" wrong" moment. With "CLEANUP_AHEAD" all instance are still alive and can be called.
    Think about protocol instance. Maybe UnifAce will destroy the protocol (instance) before doing the last chance write and then ...?  (smile)


    There are much more things behind the curtain.

    Hope I could gave you a hint what one can do to make a component plugable (smile)


    Ingo

    1. Gianni Sandigliano

      Hi Ingo,

      thanks for your detailed description of the kind of modularization you are working with daily.

      Your modularization is for your application...my post is about something much more basic level!

      Let's think about:
      - any integration with a piece of software owned/driven from an external company (Like Google Universe: Mail, Map, Calendar, Translator, ...): for each of them you need to have first a basic module, then you build your needs on top of it.
      - any addendum to Uniface to manage external devices: for each of them you need to have first a basic module, then you build your needs on top of it.
      - any addendum to Uniface Proc Script language like new function(s), new instruction(s) could be other basic modules to build application needs on top of them.

      An example: I remember another post about interfacing German Tax services; I imagine it was first built a module to interface basic tech stuffs then application needs on top of it.

      All these modules could be PLUGINS!

      In other development environment they are often called "libraries".

      I will add a comment to my initial post sharing an example.

      Gianni

    CommentAdd your comment...
  3.  
    1
    0
    -1

    Hi Gianni,

    I'm not sure about what you mean, but I understand it as creating "Uniface"-plugins for Uniface-programs.
    So, it should be a self contained uar that can be plugged in using the asn file. The plugin may have its own asn-file if needed.

    Here an example of an operation-trigger of a service (the same can be used for forms) in the self-contained uar. The INIT-operation changes the $variation to one used by the self-contained uar to  find messages etc., the CLEANUP-trigger sets the $variation back to the $variation used by the calling program and the SENDCUSTOMER is  quit by EXIT(0) so that the CLEANUP-operation is activated:

    operation INIT
      $VARTEMP$=$variation
      $variation="SC"
    end; INIT
    
    operation CLEANUP
      $variation=$VARTEMP$
    end; INIT
    
    
    operation SENDCUSTOMER
    params
    ........
      numeric OUTSTATUS  : OUT
    endparams
    
      activate "EG_WEBSERVICE".SENDCUSTOMER(.....)
      If(OUTSTATUS < -49)
      else
        if()........
      endif
      exit(0)
    end; SENDCUSTOMER
    
    

    There is a while since I thought about this, but I hope that I remember correctly. In the above specific example the SENDCUSTOMER calls a web-service, so the integration is done even further out from the Uniface uar.

    This was my contribution to get more comments.


    Regards RogerW.


    1. Gianni Sandigliano

      Hi Roger,

      Yes, Uniface plugins for Uniface applications!
      A self-contained UAR is a piece of my idea too...
      You configure the UAR, and probably few other lines, in your ASN file and voilà, it works...You start to use it!
      On top of your description:
      - same way like $variation also $language should be saved/restored
      - all operations should always exit($status) as:  0 = OK, <0 = An error, >0 = A warning

      Anyhow I have already other specs in mind but I would like to hear from unifacers first...
      I strongly feel probably I am not the first one to think about this concept.

      Thanks for your reply.

      Gianni

    2. Roger Wallin

      Hi, 

      You have to check that the "operation CLEANUP" is executed. there was some kind of problems there. But it's probably executed whatever you return in exit($status)....
      I usually use the outstatus out-parameter, which also can be checked.
      And Yes, $language could be crucial, depending on the situation.


      operation SENDCUSTOMER
      params
      ........
        numeric OUTSTATUS  : OUT
      endparams
      
        activate "EG_WEBSERVICE".SENDCUSTOMER(.....)
        If($status < -49)
          OUTSTATUS = $status
        else
          if()........
          ;Set OUTSTATUS
        endif
        exit(0)
      end; SENDCUSTOMER

      Regards RogerW.

    3. Gianni Sandigliano

      Hi Roger,

      I made already few checks with a service.
      As of today (9.7.05.030) cleanup() is always called also when service is exiting with $status less than zero.
      Here logs of my three checks respectively with -1, 0, 1:


      Starting GT0 mode...current $variation and $language:
      USYS
      USA
      Into INIT() operation...
      Into TEST() operation...Called with pStatus=1
      MYVAR
      MYL
      Into CLEANUP() operation...

      GT0: Result outside:
      $status = 1
      USYS
      USA


      Starting EQ0 mode...current $variation and $language:
      USYS
      USA
      Into INIT() operation...
      Into TEST() operation...Called with pStatus=0
      MYVAR
      MYL
      Into CLEANUP() operation...

      EQ0: Result outside:
      $status = 0
      USYS
      USA


      Starting LT0 mode...current $variation and $language:
      USYS
      USA
      Into INIT() operation...
      Into TEST() operation...Called with pStatus=-1
      MYVAR
      MYL
      Into CLEANUP() operation...
      LT0: Result outside:
      $status = -1
      USYS
      USA


      Regards,
      Gianni

    CommentAdd your comment...