DDR LISTER and multiples

366 views
Skip to first unread message

Robert Durkin

unread,
Jan 2, 2013, 3:22:31 PM1/2/13
to hardhats
I use the "DDR LISTER" RPC to get data from arbitrary files from an
application outside of VistA, and it's quite handy for this purpose.

However, a weakness of this RPC is its inability to return word
processing fields and multiples.

Is there any to make this work, or an alternative means for getting
these types of fields short of a custom RPC?

Thanks,
Rob

Sam Habiel

unread,
Jan 2, 2013, 3:42:27 PM1/2/13
to hardhats
Rob,

I am on the Fileman Development team. You can find more info on the project here:
http://www.osehra.org/group/fileman-and-lab-agile-project-flap

The DDR LISTER belongs to the Fileman Delphi Components package but is used by other applications.

It's a wrapper for LIST^DIC (http://www.hardhats.org/fileman/pm/db_dic_l.htm). LIST^DIC is a silent API that returns a list of entries for GUIs so that users pick an entry. It's not designed for searching or retrieving data.

Why don't you try DDR GETS ENTRY DATA, a wrapper for GETS^DIQ (http://www.hardhats.org/fileman/pm/db_diqgs.htm).

If you write a new Mumps routine that is in pretty good shape, I would be willing to consider its inclusion in Fileman.

Sam


Robert Durkin

unread,
Jan 2, 2013, 4:48:55 PM1/2/13
to hardhats
Hi Sam,

Thanks for recommending that I look at DDR GETS ENTRY DATA. I did so
and I found that it works great for WP fields, but still chokes on
multiples.

Should I expect that this RPC would work with multiples, or maybe I'm
somehow using it wrong?

Thanks,
Rob

Sam Habiel

unread,
Jan 2, 2013, 4:52:42 PM1/2/13
to hardhats
Check the documentation. You can do it.

Sam

Robert Durkin

unread,
Jan 2, 2013, 5:02:47 PM1/2/13
to hardhats
A nice way of saying "RTFM". :)

I followed your advice and found what I needed to make this work.

Thanks Sam!

Sam Habiel

unread,
Jan 2, 2013, 5:32:43 PM1/2/13
to hardhats
Wasn't quite saying that :)  I personally have never used this RPC, so I am uncertain whether it maps one to one to GETS^DIQ.

But if you can share your code, I would appreciate it. We can put it on a wiki.

What language are you using? Delphi, C# or something else?

Sam

Robert Durkin

unread,
Jan 3, 2013, 3:39:08 PM1/3/13
to hardhats
Sam,

I developed a couple of Java libraries that wrap around VistaLink and
a Java implementation of the RPC Broker client. The libraries allow
one to call RPCs in an object-oriented manner, and they return objects
encapsulating the pieced results from VistA.

Both of these libraries include classes that encapsulate the DDR
LISTER and DDR GETS ENTRY functionality.

Here's an example of how the DdrLister class might be used to retrieve
pending outpatient orders for a given patient:

RpcBroker rpcBroker = new RpcBroker("127.0.0.1", 9260);
rpcBroker.doSignon("access", "verify");
DdrLister query = new DdrLister(rpcBroker);
query.setFile("52.41");
query.setFields(".01;1;1E;2;2E;6E;11E");
query.setFlags("IP");
query.setXref("P");
query.setFrom("1019998");
query.setPart("1019999");
List<String> response = query.execute();
for (String line : response) {
System.out.println(line);
}

These classes are useful in that they allow a developer such as myself
to get at data that may not be available via standard CPRS RPCs.

Rob

David Whitten

unread,
Jan 3, 2013, 6:08:55 PM1/3/13
to hard...@googlegroups.com
Rob,
I'd like to understand this, even if I'm not a guru.
Could you critique my code analysis ?

On Thu, Jan 3, 2013 at 3:39 PM, Robert Durkin <robert...@gmail.com> wrote:
> Sam,
>
> I developed a couple of Java libraries that wrap around VistaLink and
> a Java implementation of the RPC Broker client. The libraries allow
> one to call RPCs in an object-oriented manner, and they return objects
> encapsulating the pieced results from VistA.
>
> Both of these libraries include classes that encapsulate the DDR
> LISTER and DDR GETS ENTRY functionality.
>
> Here's an example of how the DdrLister class might be used to retrieve
> pending outpatient orders for a given patient:
>
Thank you for sharing this code fragement.
I assume it is Java code, and it is from one of your private repositories,
as I didn't see it on github.com

My analysis follows

> RpcBroker rpcBroker = new RpcBroker("127.0.0.1", 9260);

This says there is a Java data type named RpcBroker and a variable
named rpcBroker which is of that data type. The variable gets initialized to
a new object returned by calling RpcBroker method with two arguments.
(one a TCP/IP address as a string, and the other a TCP/IP port on the machine
identified by that address. The 127.0.0.1 identifies the current machine which
may also be referred to as the "home machine" or as the "localhost"

The port number 9260 has a program listening to that port, which speaks
the VA RPC Broker protocol. According to what you mentioned earlier,
this is running VistALink, but you didn't mention whether version 1.5 or 1.6
On the Vista/MUMPS side, this will be a program in XOB namespace, possibly
invoked through xinet.d which will call the MUMPS code from a command script.

> rpcBroker.doSignon("access", "verify");

The rpcBroker variable is a Java Object, which has a method named "doSignon".
This method has two arguments, one of which is an access code and the other
a verify code. These two arguments are passwords which together uniquely
identify a particular person's access to VistA. The particular person
on the VistA
side is identified by a number which is stored in the local variable DUZ. That
number is used as an Internal Entry Number (IEN) in the FIleMan File named NEW
PERSON, File number #200, and which is an index into the global
variable ^VA(200)
That record has information about what access is allowed on the VistA system,
specifying what BROKER CONTEXTS exist, including what REMOTE PROCEDURE
calls may be made, on behalf of that user.

> DdrLister query = new DdrLister(rpcBroker);

The Java Class (datatype) named DdrLister is used to create a new variable named
query initialized by calling the DdrLister method and using the
rpcBroker object as an input.

> query.setFile("52.41");
> query.setFields(".01;1;1E;2;2E;6E;11E");
> query.setFlags("IP");
> query.setXref("P");
> query.setFrom("1019998");
> query.setPart("1019999");

These setup the various inputs to the query call, similar to the
discussion on Joe Gillon's web page:
http://vistacowboy.com/?q=content/school-house/rpcs/ddr-lister

> List<String> response = query.execute();

This creates a variable named response which is a list of strings
stored after calling the execute method on the query object.

> for (String line : response) {
> System.out.println(line);
> }

This loops through the response variable as an array, displaying each
line on the screen, using the Java system method System.out.println
to output it on a standard
output file (the Java equivalent of Unix's STDOUT)

Robert Durkin

unread,
Jan 3, 2013, 10:17:29 PM1/3/13
to hardhats
Hello David,

> Rob,
> I'd like to understand this, even if I'm not a guru.
> Could you critique my code analysis ?

Thanks for taking the time to examine the bit of code I posted. You
are obviously an experienced programmer in other languages, and appear
to have a very good handle on Java.


> Thank you for sharing this code fragement.
> I assume it is Java code, and it is from one of your private repositories,
> as I didn't see it on github.com

The Java libraries I mentioned were developed within the VA (I am a VA
developer) and are used in production. I do not have them posted on
any public repository at present, but would be glad to make them
available to anyone who is interested. JavaBroker, the library that
encapsulates the RPC broker client, is quite a bit simpler than
VistaBroker, the library that makes use of VistaLink, because the
latter library is deployed on a Java Enterprise server whereas the
former is standalone.


> My analysis follows
>
>> RpcBroker rpcBroker = new RpcBroker("127.0.0.1", 9260);
>
> This says there is a Java data type named RpcBroker and a variable
> named rpcBroker which is of that data type. The variable gets initialized to
> a new object returned by calling RpcBroker method with two arguments.
> (one a TCP/IP address as a string, and the other a TCP/IP port on the machine
> identified by that address. The 127.0.0.1 identifies the current machine which
> may also be referred to as the "home machine" or as the "localhost"
>
> The port number 9260 has a program listening to that port, which speaks
> the VA RPC Broker protocol. According to what you mentioned earlier,
> this is running VistALink, but you didn't mention whether version 1.5 or 1.6
> On the Vista/MUMPS side, this will be a program in XOB namespace, possibly
> invoked through xinet.d which will call the MUMPS code from a command script.

Yes, your analysis of this line of code is correct. This code simply
creates an instance of the RpcBroker class, passing the VistA host and
port number via the constructor. RpcBroker is a Java implementation
of the RPC Broker client (not VistaLink). It works the same way as
the Delphi client that CPRS makes use of.


>> rpcBroker.doSignon("access", "verify");
>
> The rpcBroker variable is a Java Object, which has a method named "doSignon".
> This method has two arguments, one of which is an access code and the other
> a verify code. These two arguments are passwords which together uniquely
> identify a particular person's access to VistA. The particular person
> on the VistA
> side is identified by a number which is stored in the local variable DUZ. That
> number is used as an Internal Entry Number (IEN) in the FIleMan File named NEW
> PERSON, File number #200, and which is an index into the global
> variable ^VA(200)
> That record has information about what access is allowed on the VistA system,
> specifying what BROKER CONTEXTS exist, including what REMOTE PROCEDURE
> calls may be made, on behalf of that user.

Yes, right again. This method actually returns the user's DUZ if the
sign-on was successful, otherwise it returns 0. So if you wanted the
user's duz you would assign the result of the method to a variable of
type long, as follows:

long duz = rpcBroker.doSignon("access", "verify");


>> DdrLister query = new DdrLister(rpcBroker);
>
> The Java Class (datatype) named DdrLister is used to create a new variable named
> query initialized by calling the DdrLister method and using the
> rpcBroker object as an input.
>

Yes, an instance of DdrLister is created and referenced by the
variable named query. The DdrLister object makes use of the rpcBroker
instance to invoke calls on the VistA RPC Broker.


>> query.setFile("52.41");
>> query.setFields(".01;1;1E;2;2E;6E;11E");
>> query.setFlags("IP");
>> query.setXref("P");
>> query.setFrom("1019998");
>> query.setPart("1019999");
>
> These setup the various inputs to the query call, similar to the
> discussion on Joe Gillon's web page:
> http://vistacowboy.com/?q=content/school-house/rpcs/ddr-lister
>

Yes, Joe Gillon's C# code in MDWS was actually the inspiration for my
DdrLister class. I couldn't have done it without Joe!


>> List<String> response = query.execute();
>
> This creates a variable named response which is a list of strings
> stored after calling the execute method on the query object.
>

Yes, calling execute invokes the business logic encapsulated within
DdrLister, which returns a list of strings containing the results of
the "DDR LISTER" RPC.


>> for (String line : response) {
>> System.out.println(line);
>> }
>
> This loops through the response variable as an array, displaying each
> line on the screen, using the Java system method System.out.println
> to output it on a standard
> output file (the Java equivalent of Unix's STDOUT)
>

Yes, although technically response is not an array, but the concept is the same.

Skip

unread,
Jan 4, 2013, 8:13:27 AM1/4/13
to hard...@googlegroups.com
Interesting.  I set up the call:
IN=""
IN("FIELDS")=".01;8;51*"
IN("FILE")=200
IN("FLAGS")=""
IN("IENS")="1,"
and did the following:
FOIA>ZB GETSC+5^DDR2

FOIA>S IN("FIELDS")=".01;8;51*"

FOIA>K OUT S OUT=""

FOIA>D GETSC^DDR2(.OUT,.IN)

 S N=0
 ^
<BREAK>GETSC+5^DDR2
FOIA 2d1>ZW

%ANS=""
%H="62826,28276"
DDR=""
DDR("FIELDS")=".01;8;51*"
DDR("FILE")=200
DDR("FLAGS")=""
DDR("IENS")="1,"
DDRDATA=""
DDRFILE=200
DDRFLAGS=""
DDRFLDS=".01;8;51*"
DDRIENS="1,"
DDRRSLT("200","1,",".01")="TESTMASTER,USER"
DDRRSLT("200","1,","8")=""
DDRRSLT("200.051","1,1,",".01")="XUPROG"
DDRRSLT("200.051","1,1,","1")=""
DDRRSLT("200.051","1,1,","2")="DEC 11, 1997"
DDRRSLT("200.051","1,1,","3")=""
DDRRSLT("200.051","12,1,",".01")="XUSCREENMAN"
DDRRSLT("200.051","12,1,","1")="TESTMASTER,USER"
DDRRSLT("200.051","12,1,","2")="FEB 16, 1999"
DDRRSLT("200.051","12,1,","3")=""
DDRRSLT("200.051","2,1,",".01")="XUMGR"
DDRRSLT("200.051","2,1,","1")=""
DDRRSLT("200.051","2,1,","2")="DEC 11, 1997"
DDRRSLT("200.051","2,1,","3")=""
DDRRSLT("200.051","3,1,",".01")="XUPROGMODE"
DDRRSLT("200.051","3,1,","1")=""
DDRRSLT("200.051","3,1,","2")="DEC 11, 1997"
DDRRSLT("200.051","3,1,","3")=""
DDRRSLT("200.051","374,1,",".01")="ROR VA IRM"
DDRRSLT("200.051","374,1,","1")="TESTMASTER,USER"
DDRRSLT("200.051","374,1,","2")="MAR 30, 2004"
DDRRSLT("200.051","374,1,","3")=""
DDRRSLT("200.051","43,1,",".01")="DIEXTRACT"
DDRRSLT("200.051","43,1,","1")="TESTMASTER,USER"
DDRRSLT("200.051","43,1,","2")="FEB 16, 1999"
DDRRSLT("200.051","43,1,","3")=""
DDRRSLT("200.051","8,1,",".01")="XUFILEGRAM"
DDRRSLT("200.051","8,1,","1")="TESTMASTER,USER"
DDRRSLT("200.051","8,1,","2")="FEB 16, 1999"
DDRRSLT("200.051","8,1,","3")=""
DDRRSLT("200.051","95,1,",".01")="IBDF IRM"
DDRRSLT("200.051","95,1,","1")="TESTMASTER,USER"
DDRRSLT("200.051","95,1,","2")="APR 17, 2003"
DDRRSLT("200.051","95,1,","3")=""
DDRSCRN=""
DDRXREF=""

and as you can see the data is there all fat, dumb, and happy.  However, it is not being returned:
FOIA>ZW OUT
OUT=""
OUT(1)="[Data]"
OUT(2)="200^1^.01^^"
OUT(3)="200^1^8^^"

Robert since you work for the VA, I would suggest that you file a Remedy ticket.

Skip

unread,
Jan 4, 2013, 8:59:44 AM1/4/13
to hard...@googlegroups.com
Brief note - I looked at the Help file and it indicated to me that these calls were designed to view the files as flat file and retrieve data accordingly.  Since subfile/multiples are just files within files, what you need to do is treat a subfile/multiple as if it were a separate file.  That is just my guess and that is why subfile data is not being retrieved.

Sam Habiel

unread,
Jan 4, 2013, 12:40:14 PM1/4/13
to hardhats
Rob,

A couple of things missing from you example which are very important:
1. You need to set the division (DUZ(2) using XUS {G,S}ET DIVISION call.
2. You need to set the context; otherwise your call only works for people holding the XUPROGMODE key.

Thank you for the code.

Sam


--

Robert Durkin

unread,
Jan 4, 2013, 1:01:27 PM1/4/13
to hardhats
Hi Sam,

A lot of the details of setting up the call are taken care of by the
class itself, including setting the division and context.

Actually, the division is set by RpcBroker upon successful signon.
And RpcBroker takes care of setting the context just before the "DDR
LISTER" RPC is invoked by the DdrLister class.

The DdrLister class is fairly high-level, in that it exposes only the
inputs and actions that a high-level consumer might need, and nothing
more. The lower-level details are taken care of by lower-level
classes that the consumer doesn't need to worry about.

Hope this makes sense.

Rob

Chris

unread,
Jan 4, 2013, 1:57:36 PM1/4/13
to hard...@googlegroups.com
Well hello there fellow VA developer... might I interest you in another cup of Joe?
Where might your repo be in the VA?

Feel free to reach me at chris[d0t]uyehara[@t]va[.]gov

David Whitten

unread,
Jan 4, 2013, 2:01:46 PM1/4/13
to hard...@googlegroups.com
On Fri, Jan 4, 2013 at 1:01 PM, Robert Durkin <robert...@gmail.com> wrote:
>>>> Yes, right again.  This method actually returns the user's DUZ if the
>>>> sign-on was successful, otherwise it returns 0.  So if you wanted the
>>>> user's duz you would assign the result of the method to a variable of
>>>> type long, as follows:
>>>>
>>>> long duz = rpcBroker.doSignon("access", "verify");
>>>>

Since DUZ sometimes has a fraction, you might run into a problem with code like this.
I know there are at least two fractional DUZ values:

>S I=0 F  S I=$O(^VA(200,I)) Q:I'=+I  W:I#1 !,I,?10,$P(^VA(200,I,0),"^")
.5        POSTMASTER
.6        SHARED,MAIL

Is this a bug in the return signature of the rpcBroker.doSignon method?

Best Wishes,

David

Robert Durkin

unread,
Jan 4, 2013, 2:14:18 PM1/4/13
to hardhats
Hi Chris,

I've come across your Java RPC broker client project before, but
haven't yet taken the time to experiment with it. Our encounter here
on Hardhats provides me with a great excuse to take a look at your
work.

Which facility or organization within the VA do you work for? I'm
with Loma Linda.

Rob

Robert Durkin

unread,
Jan 4, 2013, 2:18:50 PM1/4/13
to hardhats
Hi David,

You're absolutely right. An integer data type is not the best choice
to store things like DUZs and IENs. In fact, when I wrote
VistaBroker, which is the JEE version of JavaBroker, I used the Java
String class to reference these things rather than the long data type.

Although I've never run into problems with fractional DUZs, and
JavaBroker has been in production at several VA facilities for around
seven years, I believe it would be worthwhile to refactor JavaBroker
to use strings as the data type for DUZs, DFNs, and IENs.

Thanks for the heads up on this.

Rob


> Since DUZ sometimes has a fraction, you might run into a problem with code
> like this.
> I know there are at least two fractional DUZ values:
>
>>S I=0 F S I=$O(^VA(200,I)) Q:I'=+I W:I#1 !,I,?10,$P(^VA(200,I,0),"^")
> .5 POSTMASTER
> .6 SHARED,MAIL
>
> Is this a bug in the return signature of the rpcBroker.doSignon method?
>
> Best Wishes,
>
> David
>

deepanshu lakra

unread,
Mar 27, 2025, 11:01:06 AM3/27/25
to Hardhats
Hi Rob,

I am using your java RPC broker from VHAINNOVATIONS github repo. By using your implementation of DDR GETS ENTRY DATA, I am able to get WP fields but still not able to get multiples. Can you please help me here ?

The relevant code section :-
 
DdrGetsEntry ddrGetsEntry = new DdrGetsEntry(rpcBroker);
ddrGetsEntry.setFields(".01;.02;.03;.04;.05;.06;.07;.08;.09;.1;.11;1;3;2*");
ddrGetsEntry.setFile("8994");
ddrGetsEntry.setFlags("IE");
ddrGetsEntry.setIens("1595,");
List<String> responseStringLst = ddrGetsEntry.execute();
for(String responseStr: responseStringLst)
  System.out.println(responseStr);

Output :-

[Data]
8994^1595^.01^DSIC DM ADD/DELETE QUEUE^DSIC DM ADD/DELETE QUEUE
8994^1595^.02^UPD^UPD
8994^1595^.03^DSICDM^DSICDM
8994^1595^.04^1^SINGLE VALUE
8994^1595^.05^A^AGREEMENT
8994^1595^.06^^
8994^1595^.07^^
8994^1595^.08^^
8994^1595^.09^^
8994^1595^.1^^
8994^1595^.11^^
8994^1595^1^[WORD PROCESSING]
This will allow you to add or delete an entry to file 19621. When you
use the VistA Imaging import an image API, you are returned a queue
number. This number means that VistA Imaging background processor
accepted your request and place it a queue and will process it in due
time. After you get this successful queue message you should immediately
file that data through this RPC.
 
This file is to allow communication between the VistA Imaging background
processor and the DSS Document Management system.
$$END$$
8994^1595^3^[WORD PROCESSING]
Returns a string:
 If successfully added return 1^message^TRANID
 If successfully deleted return 1^message
 If unsuccessful return -1^error message
$$END$$

As you can see there is no information above for field #2 that is input parameters that happen to be multiples. Though I can view the information for field #2 in fileman using GETS^DIQ. Can you please point me what I am doing wrong here and what is the possible solution ?

Thanks,
Deepanshu
Reply all
Reply to author
Forward
0 new messages