Enrico Parisi · Nov 29, 2023 go to post

Where does that code comes from?

It seems that your method expect a %Status as returned value, try with:

Quit tSC

Like you did in your first example.

Enrico

Enrico Parisi · Nov 30, 2023 go to post

Hi Nicki,

that's EXACTLY the point of the two different calls Sync/Async (the second option commented) in my sample.

If you need to wait for the task to finish (whatever it takes, maybe longer that call interval), then use SendRequestSync() call. Using SendRequestSync() if task takes longer than time interval then when it finishes the call is performed immediately because time interval has already expired.

If you need to call the task on every call interval, regardless the previous call has finished, then use SendRequestAsync() call.

Enrico

Enrico Parisi · Nov 30, 2023 go to post

I would create my "custom" datatype extending %Library.DateTime:

Class Community.dt.CustomDateTime Extends%Library.DateTime
{

/// Converts the %TimeStamp value to the canonical SOAP encoded value.ClassMethod LogicalToXSD(%valAs%TimeStamp) As%String [ ServerOnly = 1 ]
{
	Set%val=##class(%Library.TimeStamp).LogicalToXSD(%val)
	Quit$translate(%val,"TZ"," ")
}

}

Then in your class define your property as:

Property OPDT As Community.dt.CustomDateTime;

Are you sure you really need %Library.DateTime and not %Library.TimeStamp?
The difference is the JDBC/ODBC format.

If you prefer using %Library.TimeStamp, then change the superclass in my sample code.

Enrico

Enrico Parisi · Nov 30, 2023 go to post

They are both possible solutions, however if you create a custom datatype you can then use it in any other property and class, without the need to implement <PropertyName>LogicalToXSD() for each property in each class.

Enrico

Enrico Parisi · Nov 30, 2023 go to post

I tried to join 10 minutes before the start (20 minuts ago)  but it's no longer possible:

Ooops!

Sorry friend, looks like this challenge is no longer available.

Enrico

Enrico Parisi · Dec 1, 2023 go to post

Hi Rochdi,

you provide very few details about you environment, some can be guessed.

You talk about using a services in a production and error 404, so I guess you have a business service using a SOAP inbound adapter or an HTTP inbound adapter and using a local port instead of the web server (Standard request is not enabled).

Since you do get a response (404 error is a response) when using that specific port, then the server is responding and your service works correctly with a different port, then a possibility is that that port you want to use is altready used by another HTTP/SOAP service.
If so, then when your business service starts you can check the Event Log and you probably find an error rhat th port cannot be opened.
You can also check that if you don't start your business service you still get 404 error.

But...this are only guesses, please provide more details.

Enrico

Enrico Parisi · Dec 1, 2023 go to post

I'm not sure you can "revoke start transaction" in some form, but the risk is that if the transaction start fail the tool will exit/fail the entire query.

Do you know by chance what tool is used?
Is it using JDBC or ODBC?

Enrico

Enrico Parisi · Dec 1, 2023 go to post

Hi Ian, I guess in the copy/paste something went wrong 😉
Same code with different formatting:

ClassMethod ValidNHS(pNHS As%String = "", Output pFailReason) As%Boolean
{
    IF pNHS'?10N {
        set pFailReason = "Num"Quit0
    }
    set nCheckdigit = $Extract(pNHS,10,10)
    set nChi9Digits = $Extract(pNHS,1,9)
    set nMultFact = 2set nCalcCheckdigit = 0for i = 9 : -1 : 1 {
        set nThisDigit = $Extract(nChi9Digits,i,i)
        set nCalcCheckdigit = nCalcCheckdigit + (nThisDigit * nMultFact)
        set nMultFact = nMultFact + 1
    }
    set nCalcCheckdigit = (nCalcCheckdigit # 11)
    set nCalcCheckdigit = 11 - nCalcCheckdigit
    if (nCalcCheckdigit = 10) {
        set pFailReason = "ChkDig"Quit0
    }
    if (nCalcCheckdigit = 11) {
        set nCalcCheckdigit = 0
    }
    if (nCheckdigit = nCalcCheckdigit) {
        set pFailReason = ""Quit1
    } Else {
        set pFailReason = "ChkDig match"Quit0
    }
}
Enrico Parisi · Dec 1, 2023 go to post

I'm afraid you cannot use the syntax shortcut () within a StrReplace function.
You can use the () syntax to assign a constant string to ALL the repeating fields, like:

<assignvalue='"PDF"'property='target.{PIDgrpgrp().ORCgrp().OBXgrp().OBX:ValueType}'action='set' />

In your case you need to iterate in each of the 3 repeating segments using foreach actions, like:

<foreachproperty='source.{PIDgrpgrp()}'key='k1' ><foreachproperty='source.{PIDgrpgrp(k1).ORCgrp()}'key='k2' ><foreachproperty='source.{PIDgrpgrp(k1).ORCgrp(k2).OBXgrp()}'key='k3' ><assignvalue='..ReplaceStr(source.{PIDgrpgrp(k1).ORCgrp(k2).OBXgrp(k3).OBX:ValueType},"ED","PDF")'property='target.{PIDgrpgrp(k1).ORCgrp(k2).OBXgrp(k3).OBX:ValueType}'action='set' /></foreach></foreach></foreach>

Enrico

Enrico Parisi · Dec 3, 2023 go to post

Hi Anna,

the error you are getting is due to the missing (not started) Java Gateway using port 55555.
You can get your sample working starting the default java gateway using the Management portal System Administration -> Configuration -> Connectivity -> External Language Servers, there you can customize the "%Java Server" and start it.
Note that the default "%Java Server" uses port 53273, so if you want to use it, you need to change 55555 with 53273, or you can define and start your own Java Server using port 55555.

Please note that you are using a legacy feature that should work for backward compatibility but it's no longer documented (the documentation page you have linked before editing your question is from Ensemble 2018, not IRIS).
The new documented way to call external languages, including Java, is using InterSystems External Servers ($system.external)

The following is a rewrite of the old version sample described in this page using the new External Server for Java that implement the same functionality.

Set paramsJSON="{""origin"" : ""philadelphia"", ""destination"" : ""boston""}"; Get the Java Gateway, if needed this will also start the gateway.; You may need to configure Java Home from Management Portal:; System Administration -> Configuration -> Connectivity -> External Language Servers; there you can cofigure the "%Java Server" Set jgw=$system.external.getJavaGateway()
    Do jgw.addToPath("/path/to/jars/gson-2.10.1.jar")

    Set inputJSON=jgw.new("com.google.gson.JsonParser").parse(paramsJSON)
    Set jsonObject = inputJSON.getAsJsonObject()
    Set origin = jsonObject.get("origin").toString()
    Set destination = jsonObject.get("destination").toString()
    
    Set URLsource=jgw.new("java.net.URL","http://maps.googleapis.com/maps/api/directions/json?origin="_origin_"&destination="_destination_"&sensor=false")

    Set in=jgw.new("java.io.BufferedReader",jgw.new("java.io.InputStreamReader",URLsource.openStream(),"UTF-8"))
    Set outputJSON=jgw.new("com.google.gson.JsonParser").parse(in)
    Do in.close()
    Set jsonObject = outputJSON.getAsJsonObject()
    Set response = jsonObject.toString()
    ; just for testing write the output to terminalWrite response
    

Please note that this sample does not require any Java side code, just the libraries/jars used in the sample.
For complex Java code a Java side wrapper class (or classes) can be developed to simplify the IRIS/Java interface.

HTH
Enrico

Enrico Parisi · Dec 3, 2023 go to post

I see a few issues in your sample.

First, it's no clear what' your goal, what do you need to do with the received json?

Note that what is posted:
{"facility_id":"123456789", "print_job_request"}
is not a valid json, so whatever you do, it will fail.

The ObjectToJSONStream() method "convert" an object to a JSON stream.
In your case you have a json stream and.....I'm not sure what you need to do.

Assuming the json is valid (and now isn't) you can load the json stream into a %Library.DynamicObject using:

Set dynOBJ={}.%FromJSON(pInput)

Now you can access properties like:

Set ^data=dynOBJ."facility_id" ; quotes are needed because of _

To get the json string back:

Set ^data(1)=dynOBJ.%ToJson()

HTH,

Enrico

Enrico Parisi · Dec 4, 2023 go to post

Are you calling %FromJSON passing a valid JSON or an invalid JSON?
If you have an invalid JSON, whatever you do, it will fail.

If you pass an invalid JSON, then:

USER>w $zv
Cache for Windows (x86-64) 2018.1.2 (Build 309U) Mon Mar 4 2019 15:05:44 EST
USER>Set stream=##class(%Stream.TmpCharacter).%New() 
USER>Do stream.Write("{""facility_id"":""123456789"", ""print_job_request""}")
USER>Set dynOBJ={}.%FromJSON(stream)
<THROW>%FromJSON+37^%Library.DynamicAbstractObject.1 *%Exception.General Parsing error 3 Line 1 Offset 48

If you pass a valid JSON:

USER>w $zv
Cache for Windows (x86-64) 2018.1.2 (Build 309U) Mon Mar 4 2019 15:05:44 EST
USER>Set stream=##class(%Stream.TmpCharacter).%New() 
USER>Do stream.Write("{""facility_id"":""123456789"", ""print_job_request"":""123""}")
USER>Set dynOBJ={}.%FromJSON(stream)
USER>write dynOBJ.%ToJSON()
{"facility_id":"123456789","print_job_request":"123"}
USER>

POST or GET depends on what's your goal, what your service is supposed to do.

Enrico

Enrico Parisi · Dec 4, 2023 go to post

Your question reports:

Product version: Ensemble 2018.1

My answer is for that version.

Sorry, I don't have any 2014 version available and I really don't remember if/what something is available in that old version regarding JSON.

For sure I can tell you that ##class(%Object).%FromJSON(pInput) makes no sense.
I pretty sure that %DynamicObject was not available back then (so, no {} object).

It's about time to upgrade or in fact, migrate to IRIS. 😊

Enrico

Enrico Parisi · Dec 4, 2023 go to post

I'm not sure this works in version 2014 but you can try:

ENSDEMO>Set stream=##class(%Stream.TmpCharacter).%New()
ENSDEMO>Do stream.Write("{""facility_id"":""123456789"", ""print_job_request"":""123""}")
ENSDEMO>Set sc=##class(Ens.Util.JSON).JSONStreamToObject(stream,.jsonOBJ)
ENSDEMO>Write jsonOBJ."facility_id"
123456789

Enrico

Enrico Parisi · Dec 5, 2023 go to post

Hi Luis,

how can you possibly get a <MAXSTRING> error extracting a stream from a base64 encoded property that is imported from a JSON string that is limited itself by the MAXSTRING value?

In the line:

set bodyJson = %request.Content.Read()

You get the whole JSON into a string limited to string max size.

To avoid this, you can import directly the content stream into a dynamic object:

set dynamicBody = {}.%FromJSON(%request.Content)

Enrico

Enrico Parisi · Dec 5, 2023 go to post

I don't have details of your project but when you say  "I want to use %SYSTEM.Event to process queues" and ask "Is there a way to store the queue with their messages in a Global?" I think that what you describe is exactly what an IRIS interoperability production does.

In fact, an IRIS interoperability production internally use %SYSTEM.Event to process queues and messages are indeed queued and persisted (in globals).
Within an IRIS interoperability production queued messages are preserved across system restart (and crash!), in addition messages are traced, can be resent etc etc.

So my question is, given your requirements, why not using an interoperability production instead of reinventing (or reimplementing) the wheel?

Enrico

Enrico Parisi · Dec 5, 2023 go to post

What does sqlStatus contains?

Write $system.Status.GetErrorText(sqlStatus)

Enrico

Enrico Parisi · Dec 5, 2023 go to post

I didn't realized you are still using Caché 2018! 😮

Add this to the, possibly long, list of good reasons to migrate to IRIS! 😉😊

Enrico

Enrico Parisi · Dec 5, 2023 go to post

"CALL returns an empty result"

How did you determine that? After that 3 lines, run this:

For  {Set rset=sqlResult.%NextResult() q:rset=""do rset.%Display() Write !}

I get:

1 Row Affected
1 Row Affected
1 Row Affected
1 Row Affected
name    age     home_city
Jorge   32      Tampa
Enrico  29      Turin
Dan     25      Miami
Alexy   21      London
 
4 Rows(s) Affected

You may want to check the documentation:

Returning Multiple Result Sets

Enrico

Enrico Parisi · Dec 5, 2023 go to post

You have setup your REST Web application "Allowed Authentication Method" as "Unauthenticated", therefore your REST code/application runs under the "UnknownUser" account/user.

My guess is that the UnknownUser user does not have enough privilege (Role(s)) to run your code.
If this is just a private, isolated test system, try adding %All role to the UnknownUser user account.

Enrico

Enrico Parisi · Dec 6, 2023 go to post

I would create my "custom" datatype extending %Library.DateTime:

Class Community.dt.CustomDateTime Extends%Library.DateTime
{

ClassMethod LogicalToXSD(%valAs%TimeStamp) As%String [ ServerOnly = 1 ]
{
    Set%val=##class(%Library.TimeStamp).LogicalToXSD(%val)
    Quit$translate(%val,"TZ"," ")
}

ClassMethod XSDToLogical(%valAs%String) As%TimeStamp [ ServerOnly = 1 ]
{
    Set$e(%val,11)="T"Quit##class(%Library.TimeStamp).XSDToLogical(%val)
}

}

Then in your class define your property as:

Property OPDT As Community.dt.CustomDateTime;

Are you sure you really need %Library.DateTime and not %Library.TimeStamp?
The difference is the JDBC/ODBC format. From the documetation:

%DateTime is the same as %TimeStamp (is a sub-class or %TimeStamp) with extra logic in the DisplayToLogical and OdbcToLogical methods to handle imprecise datetime input T-SQL applications are accustomed to.

If you prefer using %Library.TimeStamp, then change the superclass in my sample code.

After that:

USER>Set reader = ##class(%XML.Reader).%New() 
USER>Set sc=reader.OpenString("<NewClass2><OPDT>2023-11-30 11:07:02</OPDT></NewClass2>") 
USER>Do reader.CorrelateRoot("Samples.NewClass2") 
USER>Do reader.Next(.ReturnObject,.sc) 
USER>Do ReturnObject.XMLExport(,",indent")
<NewClass2>
  <OPDT>2023-11-30 11:07:02</OPDT>
</NewClass2>
 
USER>Write ReturnObject.OPDT
2023-11-30 11:07:02
USER>

Enrico

Enrico Parisi · Dec 6, 2023 go to post

Is Document an instance of CDM.OrderResultMsg?

If so, then Document.Orders.GetAt(1).ResultStatus should work, if not, what error you get? What is assigned to Document?

Enrico

Enrico Parisi · Dec 6, 2023 go to post

If you type in "Document.Orders.GetAt(1).ResultStatus", does it work?

If not, what error do you get?

Enrico

P.S.: what type of rule are you using?