Uniface on GitHub
Product (releases and patches)
Fixes and Updates
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!
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. The word "plugin" is used to identify a software that can easily be 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 UILGSAN_GMAP_SVC.getPathFromTo() get traveling steps between two GeoPoints|Addresses|POIs in an UILGSAN_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: firstname.lastname@example.org
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... - Should a list of Uniface plugins available be maintained on uniface.info? If yes, how?
About the UAR-Name:
I would suggest the follwing format
So the only things to manage ist the provider id.
e.g a plugin from UnifAce will be:UP_UNIFACE_GRAPHICS.uarorUP_UNIFACE_GRAPHICS_V201911.uarif this is a newer version.
Your plugins will then beUP_GIANNI_SUPERTOOL1.uarUP_GIANNI_SUPERTOOL2.uar
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.
Hi GianniNaming convention, the mother of all trouble 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 nameThe second @ spearate the types of the paramtersAnd 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 stringThis 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 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.
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 areaendparams
UIL = UnifAceItemListThe $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 ownactivate 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
CB ; CallBack-InterfaceEDIT ; Default interactive EDITGDA_GET ; Get and SET $GDA$ from outsideGDA_SET ;-"-GENERAL ; Some general things, addressed by a parameter TOPICINSTANCEPROPERTIES_GET ; GET and SET $INSTANCEPROPERIES$INSTANCEPROPERTIES_SET ; -"-OP_CPT_INFO ; Get Information about the instanceOP_GET_CLL_HANDLE ; Get the collection handle of a entityOP_GET_OCC_HANDLE ; Get a occournce handle of a entity...xxx
BTW: About INIT and CLEANUPOur 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 ...?
There are much more things behind the curtain.
Hope I could gave you a hint what one can do to make a component plugable
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.
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:
numeric OUTSTATUS : OUT
If(OUTSTATUS < -49)
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.
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.
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.
numeric OUTSTATUS : OUT
If($status < -49)
OUTSTATUS = $status
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:USYSUSAInto INIT() operation...Into TEST() operation...Called with pStatus=1MYVARMYLInto CLEANUP() operation...
GT0: Result outside:$status = 1USYSUSA
Starting EQ0 mode...current $variation and $language:USYSUSAInto INIT() operation...Into TEST() operation...Called with pStatus=0MYVARMYLInto CLEANUP() operation...
EQ0: Result outside:$status = 0USYSUSA
Starting LT0 mode...current $variation and $language:USYSUSAInto INIT() operation...Into TEST() operation...Called with pStatus=-1MYVARMYLInto CLEANUP() operation...LT0: Result outside:$status = -1USYSUSA
© 2019 Uniface Privacy & Cookies | Privacy Statement | Legal