Enrico Parisi · Nov 14, 2023 go to post

I suspect you have some inconsistency in the Character Encoding in your XML.

Is the XML Character Encoding declared? If yes, how?

i.e. does the first line contains something like "<?xml version="1.0" encoding="utf-8"?>" ?

How are you crating the %XML.XPATH.Document instance from your XML?

It would be helpful if you can post a tiny code to reproduce the issue.

Enrico

Enrico Parisi · Nov 14, 2023 go to post

"I realized that the headers are being reseted, keeping just 3 basic headers for the redirection"

Sounds/looks like a bug to me.

Enrico

Enrico Parisi · Nov 14, 2023 go to post

Out of curiosity, was the system upgraded from a Cahcé based product? (Ensemble, HealthShare etc.)

Enrico

Enrico Parisi · Nov 14, 2023 go to post

It seems that character 8211 (en dash) is not utf-8 but utf-16, google is your best friend and I'm not an expert in unicode, utf-8, utf-16 etc.! 😊

Set xml="<?xml version=""1.0"" encoding=""UTF-8""?>"
Set xml=xml_"<Text>This is n-dash "_$wc(8211)_" in xml</Text>"
Set xml=$ZCONVERT(xml,"O","UTF8")
Set sc=##class(%XML.XPATH.Document).CreateFromString(xml, .xmlDoc)
Write sc
Set sc=xmlDoc.EvaluateExpression("/Text","text()",.result)
Write result.GetAt(1).Value,!

Result:

This is n-dash – in xml

Enrico

Enrico Parisi · Nov 18, 2023 go to post

The documentation includes a lot of info about INSERT OR UPDATE Sql command, including:

"An existing row is one in which the value being inserted already exists in a column that contains a unique constraint. For more details, see Uniqueness Checks."

"When using INSERT OR UPDATE, you can only insert IDKEY column values, not update them. If the table has an IDKEY index and another UNIQUE constraint, INSERT OR UPDATE matches these columns to determine whether to perform an insert or an update. If the other key constraint fails, this forces INSERT OR UPDATE to perform an update rather than an insert. However, if the specified IDKEY column values do not match the existing IDKEY column values, this update fails and generates an SQLCODE -107 error, because the update is attempting to modify the IDKEY columns."

I suggest to read carefully the relevant documentation page.

Enrico

Enrico Parisi · Nov 18, 2023 go to post

Thank you Dan for your effort.

A possible place to share your project can be InterSystems Corporation Github where other samples like Sample.Person and other are available.

If possible it would be nice to include the next/fixed version of JDBC, if the fix it's only a new jar and not within IRIS.

Ideally all the relevant info should be added to the documentation.

Enrico

Enrico Parisi · Nov 18, 2023 go to post

Hi Yone,

it would be nice of you if you provide a feedback on the answers you receive.

Enrico 

Enrico Parisi · Nov 20, 2023 go to post

My guess/bet is that they need/want to include the specimen label(s) in PDF format.

I think that crating a custom schema with custom Z segment, possibly a repeating segment, is an option.

Enrico

Enrico Parisi · Nov 20, 2023 go to post

Difficult to tell from the limited info provided.

What I can guess is that it seems you are trying to use a serial class (HS.FHIRServer.API.Data.Request) as message.

But I might be wrong, please provide more context.

Enrico

Enrico Parisi · Nov 20, 2023 go to post

Again, difficult to tell from the limited info provided.

What are you doing after instantiating  HS.FHIRServer.API.Data.Request ?

HS.FHIRServer.API.Data.Request is a serial class, not a persistent class, are you using it in a SendRequest(Sync/Async) call? If so, then you cannot do that.

But again, this is only a guess, please provide more context.

Enrico

Enrico Parisi · Nov 21, 2023 go to post

Command pipes (CPIPE) or Named Pipes (NPIPE)??

Any little, as simple as possible, test code of what you tested?

Enrico

Enrico Parisi · Nov 23, 2023 go to post
do service.OnProcessInput(pInput,.pOutpt)

You are not supposed to call the OnProcessInput() callback method directly, instead the ProcessInput() method should be called.

Sometime calling OnProcessInput() works, sometimes create problems.

I think InterSystems should have made OnProcessInput() [private] as most of the callback methods (like %OnNew() for instance).

Enrico

Enrico Parisi · Nov 23, 2023 go to post

I'm not sure I understand your issue right, my understanding is that you receive an XML declared as UTF-8 that contains ISO-8859-1 characters.

If so, you can convert the encoding of the stream content using something like:

/// Convert the encoding of the content of a stream to UTF-8./// If OutStream is not passed (of any %Stream.* class), then a new %Stream.GlobalBinary is returned./// Note that OutStream IS NOT SAVED on exitClassMethod ConvertStreamToUTF8(InStream As%Stream.Object, ByRef OutStream As%Stream.Object = {##class(%Stream.GlobalBinary).%New()}) As%Status
{
	Set sc=$$$OKSet MaxRead=$$$MaxLocalLength\2; to be safeTry {
		While 'InStream.AtEnd {
			Set content=InStream.Read(MaxRead)
			Set sc=OutStream.Write($ZCONVERT(content,"O","UTF8"))
			If$$$ISERR(sc) Quit
		}
	} Catch CatchError {
		#dim CatchError as%Exception.SystemExceptionSet sc=CatchError.AsStatus()
	}
	Quit sc
}

If the problem is different, please provide more info/details, maybe a sample XML (not necessarily the original XML).

Enrico

Enrico Parisi · Nov 23, 2023 go to post

I've no idea why it does not works, however, why do you use % classes now days?
Today there is (IMO) a better way to implement system wide accessible classes/code without "messing" with % classes (or code in general) stored in the IRISSYS database.

Create a new database & namespace (creating namespace is optional but convenient), say you call it JIULIB and put all your system wide accessible code there with proper (unique) package naming.
In this case you can call your sample class pylib.Utility instead of %Zpy.Utility and save&compile it in your JIULIB namespace.

Then create the ("virtual") namespace called %ALL and map the package pylib to your JIULIB database and voilà, your pylib package is accessible from ALL namespaces currently defined and new ones created afterwards.

In this way you have all your lib code properly divided in your own database (may simplify upgrades) and is a more "container friendly" configuration.

Bonus: your python test works! (just tested in my system)

Today there is no good reason to use/make %* classes/code, leave %* to InterSystems.

Relevant documentation is here.

Enrico

Enrico Parisi · Nov 26, 2023 go to post

Very simple, just create a Business Service that use Ens.InboundAdapter.

The default behavior of Ens.InboundAdapter is to call the BS (ProcessInput()) every "CallInterval" seconds.

Something like:

Class Community.bs.TimedService Extends Ens.BusinessService
{

Parameter ADAPTER = "Ens.InboundAdapter";

Method OnProcessInput(pInput As%RegisteredObject, Output pOutput As%RegisteredObject) As%Status
{
	Set BpRequest=##class(Ens.Request).%New()
	Set sc=..SendRequestSync("YourBusinessProcessName",BpRequest,.BpResponse)
	;; OR, if you don't need to wait for the BP to finish:;Set sc=..SendRequestAsync("YourBusinessProcessName",BpRequest)Quit sc
}

}

Add this service to your production, to trigger every one minute set the setting CallInterval=60 (seconds).

Enrico

Enrico Parisi · Nov 26, 2023 go to post

Purging every N days should keep the database size almost constant, assuming a constant number of messages.

Unless you have some other database classes that keep growing.

Are you purging message bodies too?

What kind of messages does your production use? HL7 only? Other messages?

You may have orphaned messages in your database.

Regarding moving a CACHE.DAT, can you stop the system for the time it takes to copy the file to a different filesystem/drive?

Enrico

Enrico Parisi · Nov 26, 2023 go to post

From classreference:

Properties which can be modified for an already created database are:
    ReadOnly
    .......

So, after the creation of the database:

Set db=##Class(SYS.Database).%OpenId("/InterSystems/cachedb/mydatabase")
Set db.ReadOnly=0
Write db.%Save()

Enrico

Enrico Parisi · Nov 26, 2023 go to post

EVERY interoperability session start from a Business Service, be it from a message/call received from an external system or triggered by a timed event, like in this case.
Your problem/question is:

"I need to trigger production process/operation every minute"

That's EXACTLY what my BS sample does, all you need is to call your "process/operation" that "exchange data with external system".

This is the way to implement it.
Enrico

Enrico Parisi · Nov 27, 2023 go to post

Set inputBinaryStream=##class(%Stream.FileBinary).%New()
Set inputBinaryStream.Filename="\\server\your\share\file.xml"
Set outputBinaryStream=##class(%Stream.FileBinary).%New()
Set outputBinaryStream = ##class(Ens.Util.XML.Reader).ChangeXMLStreamEncoding(inputBinaryStream, "ISO-8859-1",outputBinaryStream, .tSC)

; Since the output stream is passed, you can just call (last line) with:
Do ##class(Ens.Util.XML.Reader).ChangeXMLStreamEncoding(inputBinaryStream, "ISO-8859-1",outputBinaryStream, .tSC)

Enrico

Enrico Parisi · Nov 27, 2023 go to post

Hi Yuri,

very interesting project.

Is there any particular reason for using Java to call a (relatively) simple REST API?

Calling a REST API can be easily implemented in IRIS directly without the "Java layer".

Enrico

Enrico Parisi · Nov 27, 2023 go to post

Simply replace the line:
//call here Do ##class(Ens.Util.XML.Reader).ChangeXMLStreamEncoding...

With:
Set outputBinaryStream=##class(%Stream.FileBinary).%New()
Do ##class(Ens.Util.XML.Reader).ChangeXMLStreamEncoding(tStream, "ISO-8859-1",outputBinaryStream, .tSC)
//you may want to check tSC, just in case....
//now on use the header changed outputBinaryStream instead of tStream

Enrico

Enrico Parisi · Nov 27, 2023 go to post

Thank you Robert for the clarification, really helpful for the community....

I just didn't realized that this article was submitted for the Java Contest, how could I have understood this from the post above? Maybe I lack a bit of imagination

Enrico

Enrico Parisi · Nov 27, 2023 go to post
Method OnRequest(pRequest As Ens.StreamContainer, Output pResponse As Ens.Response) As%Status
{ $$$LOGINFO("Inne i XmlFilterProcess")
    set filename = pRequest.OutputFilename
    set stream = pRequest.Stream
    $$$LOGINFO(stream.Read())

 set status=##class(%XML.XPATH.Document).CreateFromStream(stream,.mydoc)
 set status=mydoc.EvaluateExpression("/staff/doc/name","text()",.myresults)
 set count = myresults.Count()
 $$$LOGINFO(count)
 
  for i =1:1:count
 {
 set result = myresults.GetAt(i).Value
 $$$LOGINFO(result)
 }
    Quit status
}

You need to change this two lines:

set status=mydoc.EvaluateExpression("/staff/doc/name","1",.myresults)
set status=mydoc.EvaluateExpression("/staff/doc/name","text()",.myresults)

set result = myresults.GetAt(i)
set result = myresults.GetAt(i).Value

Enrico

Enrico Parisi · Nov 27, 2023 go to post

You can also search directly in the event log from the Management Portal

There you also get a link to the session trace.

Enrico

Enrico Parisi · Nov 27, 2023 go to post

If it's in the table, then can be viewed in the event log. All that page does is run a query  against ENS_UTIL.LOG and display the result.
From your screenshot the source config item should be ....RsltRouter, if not found in the list (I don't know why), you can just type it or omit it.

Enrico Parisi · Nov 28, 2023 go to post

Hi Summer,

thank you for the information, since then I solved my issue and have used %setall()/getall() "magic" (secret? 😉 ) methods in a couple of cases (like streams), although I'm not sure I discovered all the magic! 

The real issue is the lack of documentation and samples, for me as well as for all the community.

In addition, InterSystems use (used?) to say that what is not documented is considered not (officially) supported....

Enrico

Enrico Parisi · Nov 28, 2023 go to post

Maybe the %JSONImport method is returning an error?

To find it out change this two lines:
do pResponse.%JSONImport(tHttpResponse.Data.Read())
quit $$$OK

With:
quit pResponse.%JSONImport(tHttpResponse.Data.Read())

Then check the trace/event log.

Enrico

Enrico Parisi · Nov 28, 2023 go to post

Hi Michael,

in order for %JSONImport() method to work properly the class of "pResponse" (inheriting from %JSON.Adaptor) MUST match the structure of the JSON being imported.

From the error it seems this is not the case for your class and JSON.

Another option is to load/import the JSON stream into a dynamic object {} (%Library.DynamicObject) and then "manually" set your pResponse properties from the dynamic object properties.

Enrico

Enrico Parisi · Nov 29, 2023 go to post

Hi Emil,
I can think of 3 possible approaches.

1) Use XPATH
2) Modify the XML Document as a DOM
3) Use XSLT transformations

All 3 can be used/implemented in IRIS.

Enrico

P.S.: I suggest using the latest version of the documentation