Question Jules Pontois · Oct 19, 2023

Cette question est apparue à l'origine dans les commentaires du post : Surcharge les méthodes SendRequestAsync et SendRequestSync
 

Bonjour,

Effectivement, retirer ForceGenerate des mots clés résout le problème des doublons. Merci !

Une dernière question : Une fois le code généré, il n'est pas directement visible dans les classes crées. Et notamment en utilisant VS Code. Du coup, actuellement, je lance la compilation des sous classe avec $system.OBJ.Compile et le flag subclasses.

1
0 85
Question Jules Pontois · Oct 16, 2023

Bonjour,

Je travaille sur l'ajout d'étapes préliminaires avant l'envoi d'un message d'un Business Service à un Business Process.

Pour ce faire, je surcharge les méthodes SendRequestAsync et SendRequestSync, mettant ces étapes préliminaires au début et quittant avec ##super return.

Je veux garder le comportement natif de SendRequestAsync et SendRequestSync. Je veux aussi coller à l'utilisation de ##super, donc si ces méthodes changent dans une mise à jour annuelle d'Iris, je n'aurai rien à changer. À cet égard, la classe personnalisée que j'ai faite doit étendre Ens.BusinessService. Voici à quoi elle ressemble :

Class XXXX.OUTILS.BS.AuditCommons Extends Ens.BusinessService

{

 

/// Class of the audit to use for this flow. If the flow use

/// iterative process, for instance a loop to inserted multiple

/// lines in a table, you can use its insertdetails() method to

/// log an error that occured in the loop without poluting

/// the journal.

Property auditClass As %String(MAXLEN = 500) [ InitialExpression = "XXXX.REPORTING.Tables.Commons.Main" ];

 

/// Name of the flow that will be inserted in the audit.

Property flowName As %String(MAXLEN = 500);

 

/// Source of the flow that will be inserted in the audit.

Property flowSource As %String(MAXLEN = 500);

 

/// Target of the flow that will be inserted in the audit.

Property flowTarget As %String(MAXLEN = 500);

 

/// If true, the message will be sent synchronously.

Property asynchronous As %Boolean;

 

/// Audit instance of the current session

Property audit As XXXX.REPORTING.Tables.Commons.Main;

 

Property errMsg As %String(MAXLEN = "");

 

Parameter auditLogError = 1;

 

Parameter SETTINGS = "auditClass:flowParameters,flowName:flowParameters,flowSource:flowParameters,flowTarget:flowParameters,asynchronous:flowParameters";

 

Method SendRequestSync(pTargetDispatchName As %String, pRequest As %Library.Persistent, ByRef pResponse As %Library.Persistent, pTimeout As %Numeric = -1, pDescription As %String = "") As %Status

{

    if ..asynchronous quit ..SendRequestAsync(pTargetDispatchName, pRequest, pDescription)

    set pResponse = ""

    set sc = ..initAudit(pRequest) quit:'sc sc

    set req = ..setReq(pRequest, .sc) quit:'sc sc

    quit ##super(pTargetDispatchName, req, .pResponse, .pTimeout, pDescription)

}

 

Method SendRequestAsync(pTargetDispatchName As %String, pRequest As %Library.Persistent, pDescription As %String = "") As %Status

{

    if '..asynchronous quit ..SendRequestSync(pTargetDispatchName, pRequest, .pResponse, .pTimout, pDescription)

    set sc = ..initAudit(pRequest) quit:'sc sc

    set req = ..setReq(pRequest, .sc) quit:'sc sc

    quit ##super(pTargetDispatchName, req, pDescription)

}

 

/// Initialize an audit for the current session. You can

/// use the audit instance using the ..audit property.

Method initAudit(req As Ens.Request = "") As %Status

{

    do ..generateSession()

 

    set auditData = {

        "session": (..%SessionId)

        ,"flowName": (..flowName)

        ,"flowSource": (..flowSource)

        ,"flowTarget": (..flowTarget)

        ,"filename": (##class(XXXX.OUTILS.File.FileInfos).getFilename(req))

    }

 

    set ..audit = $CLASSMETHOD(..auditClass, "initialize", auditData, .sc)

    if 'sc return ..error("<Initialize audit>",, "initAudit", sc).AsStatus()

 

    if ..errMsg '= "" do ..audit.setError(..errMsg, ..#auditLogError)

    return 1

}

 

Method setReq(pRequest As %Library.Persistent, Output gsc As %String = 1) As Ens.Request

{

    return pRequest

}

 

Method generateSession()

{

    set (..%SessionId,$$$JobSessionId) = ##class(Ens.MessageHeader).%New().MessageId()

}

 

ClassMethod OnGetConnections(pArray As %String, item As Ens.Config.Item) As %Status

{

    do ##class(XXXX.OUTILS.Admin).linkBsToBp(.pArray, .item)

}

 

/// Method used as an alias to shorten the code.

ClassMethod error(name As %String, code As %String = "", location As %String = "", data As %String = "") As %Exception.General

{

    return ##class(%Exception.General).%New(name, code, location, data)

}

 

}

J'utilise cette classe pour créer plusieurs classes de service que j'utiliserai à la place de la classe native. Par exemple, au lieu d'utiliser EnsLib.RecordMap.Service.ComplexBatchFTPService, j'utiliserai celle-ci :

Class XXXX.OUTILS.BS.ComplexMap.FTP Extends (EnsLib.RecordMap.Service.ComplexBatchFTPService, XXXX.OUTILS.BS.AuditCommons)

{

Method SendRequestSync(pTargetDispatchName As %String, pRequest As %Library.Persistent, ByRef pResponse As %Library.Persistent, pTimeout As %Numeric = -1, pDescription As %String = "") As %Status

{

    if ..asynchronous quit ..SendRequestAsync(pTargetDispatchName, pRequest, pDescription)

    set pResponse = ""

    set sc = ..initAudit(pRequest) quit:'sc sc

    set req = ..setReq(pRequest, .sc) quit:'sc sc

    quit ##super(pTargetDispatchName, req, .pResponse, .pTimeout, pDescription)

}

 

Method SendRequestAsync(pTargetDispatchName As %String, pRequest As %Library.Persistent, pDescription As %String = "") As %Status

{

    if '..asynchronous quit ..SendRequestSync(pTargetDispatchName, pRequest, .pResponse, .pTimout, pDescription)

    set sc = ..initAudit(pRequest) quit:'sc sc

    set req = ..setReq(pRequest, .sc) quit:'sc sc

    quit ##super(pTargetDispatchName, req, pDescription)

}

 

}

Comme vous pouvez le voir, les méthodes SendRequestAsync et SendRequestSync sont également dans cette classe. C'est parce que je ne peux pas mettre ma classe personnalisée comme premier élément dans la liste des extends. Si je le fais, les méthodes et les valeurs des paramètres de Ens.BusinessService dans ma méthode personnalisée prendraient le pas sur celles de EnsLib.RecordMap.Service.ComplexBatchFTPService.

Ça fonctionne bien comme ça, mais ça me dérange aussi que ces méthodes doivent être dupliquées dans chacune de ces classes de service personnalisées. Alors voici ma question : Y a-t-il un moyen de définir les méthodes surchargées de ma classe personnalisée pour qu'elles aient la priorité ? Je voudrais que ma classe ComplexeMap et toutes les autres ressemblent à ceci :

Class XXXX.OUTILS.BS.ComplexMap.FTP Extends (EnsLib.RecordMap.Service.ComplexBatchFTPService, XXXX.OUTILS.BS.AuditCommons)

{

 

}

Nous utilisons IRIS for Windows (x86-64) 2022.1 (Build 209U)

Merci d'avance, et bonne journée.

5
0 100