A Caché of Tips - MVBasic Access to Class Properties and Methods

11 views
Skip to first unread message

Michael Cohen

unread,
Nov 1, 2011, 1:09:25 AM11/1/11
to InterSystems: MV Community
InterSystems has added a number of capabilities to MVBasic, one of
which is the ability to access class properties and methods. You can
also write your own class methods using MVBasic or other languages.
In addition, InterSystems provides a number of classes that implement
a range of functionality. These are illustrated in the standard
documentation, and some are referenced in tutorials as well. A good
way to explore the provided classes is from the 'Class Reference' tab
at the top of the Documentation Home Page. From there, in the left
frame, you can click on package names (items with triangles) at the
left to open packages to see their classes. For example, click on
package %Net and then on class SMTP to see the details of the Simple
Mail Transfer Protocol facility provided by Caché. Some developers
have used this so that when serious application errors are trapped, an
email with the details is sent to the support staff. A number of
setup steps may be required, depending on your email server and
security setup. Another commonly used package is %Stream, used to
process various types of files and objects. For today's Tip, I will
describe MVBasic access to the %XML package.

In general, MVBasic references class methods with an 'arrow' syntax:
"className"->methodName(arg1,arg2,...)
and class properties with:
"className"->propertyName

Assume I have an empty MV file PERS with a DICT:
LIST DICT PERS BY F2
Field............ CODE KEY.CODE CONV. FORMAT DISPLAY NAME SM
ASSOC.....
Name

@ID D 0 10L PERS S
FNAME D 1 15L S
LNAME D 2 15L S
NUMBER D 3 4R S
NAME I FNAME:" 20L S
":LNAME

5 Items listed.
MV:

And suppose I were to receive an .xml file with a data record, like:

<?xml version="1.0" encoding="UTF-8" ?>
<PERSON>
<PERS>
<Number>111</Number>
<Fname>JOHN</Fname>
<ItemId>1</ItemId>
<Lname>SMITH</Lname>
<Name>JOHN SMITH</Name>
</PERS>
</PERSON>

I could write code to parse the file and WRITE the record. But the
supplied %XML.Reader class provides methods that will do this for us.

Use of this class requires that we have a class that describes our MV
file.
PROTOCLASS PERS *
will create the required class. It even has the generated class
inherit from %XML.Adaptor, which is needed for this example.


This MVBasic program XML2PERS uses the class 'arrow' syntax noted
above to read the .xml file and insert the record into our MV file.

* Sample MVBasic code to read and parse an XML file
* and write the record to an MV file
* First create an XML reader
reader="%XML.Reader"->%New()
* Open the file
reader->OpenFile("C:\Temp\PERS1.xml")
* identify the outer element name that corresponds to our class
reader->Correlate("PERS","MVFILE.PERS")
* read the data and create a pers object
sc=reader->Next(pers,status)
* reference the PERS Name field
CRT "Found PERS: ":pers->ItemId
* add this to our file
sc=pers->%Save()


We can run this and examine the generated data record.

MV:COUNT PERS

[401] No items present.
MV:XML2PERS
Found PERS: 1
MV:LIST PERS NAME FNAME LNAME NUMBER

LIST PERS NAME FNAME LNAME NUMBER
PERS...... NAME................ FNAME.......... LNAME.......... NUMBER

1 JOHN SMITH JOHN SMITH 111

One item listed.
MV:


As note in the class documentation for %XML.Reader, this program could
have been a loop to process many records. We could also have examined
each record as we read it, and modified fields or rejected the record.


To reverse the process, starting with the above data record, we could
have used the %XML.Writer class to create the .xml file near the top
of this Tip.

This is MVBasic program PERS2XML that created that file.

* Class MVFILE.PERS inherits from class %XML.Adaptor, and so can
access its methods
* Start with an instance of PERS 1
p1="MVFILE.PERS"->%OpenId(1)
* Create an XML writer instance to do the work
writer="%XML.Writer"->%New()
writer.Charset="UTF-8"
* Tell the writer that it will create a file with name based on the ID
of the PERS
sc=writer->OutputToFile("C:\Temp\PERS":p1->ItemId:".xml")
* Write the header
sc=writer->RootElement("PERSON")
* Write the contents of PERS 1 with XML annotation
sc=writer->Object(p1)
* Write the footer and close the file
sc=writer->EndRootElement()* Class MVFILE.PERS inherits from class
%XML.Adaptor, and so can access its methods
* Start with an instance of PERS 1
p1="MVFILE.PERS"->%OpenId(1)
* Create an XML writer instance to do the work
writer="%XML.Writer"->%New()
writer.Charset="UTF-8"
* Tell the writer that it will create a file with name based on the ID
of the PERS
sc=writer->OutputToFile("C:\Temp\PERS":p1->ItemId:".xml")
* Write the header
sc=writer->RootElement("PERSON")
* Write the contents of PERS 1 with XML annotation
sc=writer->Object(p1)
* Write the footer and close the file
sc=writer->EndRootElement()


To summarize, MVBasic has been extended to support direct access to
class/object properties and methods, and Caché includes many packages
of classes with functionality that you may find useful.

Disclaimer: to keep things simple, this code does no error checking.





Message has been deleted

Michael Cohen

unread,
Nov 1, 2011, 1:19:41 PM11/1/11
to intersy...@googlegroups.com
A minor correction...

Although classes define properties, and PROTOCLASS creates one for each MV file field, you need a instance of a class to reference its properties.

So MVBasic can open an object corresponding to the record in the example, and reference and set the value of its properties, as:

p1="MVFILE.PERS"->%OpenId(1)
crt p1->Fname
p1->Fname="Mary"
p1->%Save()

Lee Burstein

unread,
Nov 1, 2011, 1:58:58 PM11/1/11
to intersy...@googlegroups.com
This is a general request to all of you out there. Would you please respond telling us how you have used our library of APIs? Thanks.

> --
> You received this message because you are subscribed to the Google Groups "InterSystems: MV Community" group.
> To post to this group, send email to Cac...@googlegroups.com
> To unsubscribe from this group, send email to CacheMV-u...@googlegroups.com
> For more options, visit this group at http://groups.google.com/group/CacheMV?hl=en
>


Lee H. Burstein
Product Manager
InterSystems
Office: 302-477-0180
Cell: 302-345-0810

Jason Warner

unread,
Nov 1, 2011, 4:57:38 PM11/1/11
to intersy...@googlegroups.com
We use all of the APIs very heavily. Actually, the last two about
exception handling and this one about using classes defines our error
handling almost perfectly. We've changed most of our errors that used to
do something like

OPEN "MV.FILE" to MV.FILE else STOP U002, "MV.FILE"

to

OPEN "MV.FILE" to MV.FILE else throw Brashers.FileOpenException("MV.FILE")

We then have wrapped all of our programs in a try/catch that loads up a
process private global with the information from our exceptions. When
the program falls back to the menu in an error state, we launch a
program that asks the user for information about menu items and what
they think caused the errors. All of this information along with the
data in the process private global is then written to a global that we
use as a holding pond. This global is scanned regularly by a background
task that sends out our emails. It also accesses our bug tracking
software and uses Web Services to create or update bug tracking cases
with that same information from the email.

Another example is our source control/deployment solution. We use Studio
hooks to export all of source code to our source control directory.
These are then tracked in Mercurial. Each user has at least 2 dev
namespaces on their box. Their "stable" namespace (not necessarily named
"stable") should hold the same code as our central repository. Bugs can
be fixed and pushed everywhere from that namespace. Their "dev"
namespace(s) are the experimental/breaking changes namespaces. We do our
serious development in that namespace.

We have mapped all of our routines and settings globals to another
namespace and left our data globals alone. This allows us to grab any
cache.dat from any of our live auctions (usually from last night's
backup) and drop it straight into any of our namespaces and work with
real data while not having to import code and mess with settings.

Also, all the deployment targets and scheduling is done through Zen and
ASP.Net pages. The Zen pages are for the Studio specific hooks and the
ASP.Net pages are for our management/scheduling programs.

We use web services to transfer projects around to various servers in
our testing/deployment environment and because of the hooks that Studio
gives us, we can pull that project info from a server and recreate the
project in Studio in any namespace we want. We also use web services to
update/close bugs in our bug tracking software and use the %Net.SMTP
class to notify us of compile/deployment problems.

We use the .Net gateway to give Regular Expression syntax to our MV
programs that allows easier screen scraping for some of our tools that
look at information on the web. Our screen scrapers use %Net.HttpRequest
to request and post data to web sites. Because all classes can be
extended in Cache, we've added some extensions to %Net.HttpRequest that
allow us to deal with sites that don't conform 100% to rules in the
various RFCs for the web.

As I read back through this, I hope that people don't see this as
bragging because that isn't my intention. I am just really excited that
Cache has given us the tools to be able to accomplish everything above
in a syntax and manner that we are comfortable with. We regularly ask
each other "How the heck would we have accomplished this in jBASE?". I
think that speaks highly to the toolset that Cache has provided us.

Jason

Dawn Wolthuis

unread,
Nov 1, 2011, 5:24:02 PM11/1/11
to intersy...@googlegroups.com
We have used many features that were sittin' there waiting for us in the Cache' class library. For example, when we started working with Amazon e-commerce, we found the security algorithms were already in Cache' so we could do

signature = "%SYSTEM.Encryption"->HMACSHA1(SORTED.STRING,skey)
encoded.sig = "%SYSTEM.Encryption"->Base64Encode(signature)

When we wanted to send emails, we found we could do

    mailer = "%Net.SMTP"->%New()
    mailer->smtpserver = "localhost"
    message = "%Net.MailMessage"->%New()
...
    mailer->Send(message)

We upload images using
             uploadedImage="%Stream.FileBinary"->%New()

Plus we use the %ZEN classes extensively as well as resultsets and the usual fare.

I'm guessing there are more, but those are the ones that come to mind. It is quite a nice experience to be able to use this nice mixture of MV and OO, with a delivered library of classes we can use to get the job done. We have not yet written any web services, but we plan to. Cool stuff!  --dawn
--
Dawn M. Wolthuis

Take and give some delight today

Doug Golder

unread,
Nov 1, 2011, 5:24:05 PM11/1/11
to InterSystems: MV Community
We do use the GetStored method for most properties to check if the
data has changed from the stored data and log the change [property
name]GetStored(itemid).

Another thing we have done is add brashers errmsg ie U000 to the
Exception class.

We are using the %Net class to do ftps to do banking and sending of
ACH.

oZone

unread,
Nov 1, 2011, 5:38:15 PM11/1/11
to InterSystems: MV Community
Well,

I'm sure I'll forget some things. Jason has given a pretty good
overview of what we do.

We use %Net to communicate with Banks and Vendors, transfer money via
ACH, and consume a variety of web content. We upload videos of
vehicles using Youtube's API and %Net classes.

We use %File heavily to manipulate and manage operating system files
like pictures of vehicles.

We use process private globals like ^||ProgData("stuff") very
frequently as a means of transferring data between programs,
subroutines, or classes. This has allowed us to extend the
functionality of programs without having to completely rewrite the
interfaces. The data is also thrown away when the user logs off.

We use %XML to read and create xml documents. I used correlate to
create over 400 classes that I needed to communicate with a particular
vendor in about 15 seconds. I don't even know how to quantify how much
time that saved me.

We use the utility functions on %CSP.Page to url decode or encode and
html encode or decode data.

Our entire deployment system is built using functionality in the
%System.OBJ class

We have implemented Cache Security into our system and manipulate user
roles using the Security class.

We use %ResultSet frequently to utilize class queries within our MV
basic code.

We have a suite of unit tests that we created with %UnitTest to make
sure everything works as expected before upgrading to a new version of
cache.

We are planning on using %WebStress to take down a competitor's
website.

Finally, we use the %Awesome class to just be awesome ;)

On Nov 1, 11:58 am, Lee Burstein <Lee.Burst...@intersystems.com>
wrote:
> This is a general request to all of you out there. Would you please respond telling us how you have used our library of APIs? Thanks.
>
> On Nov 1, 2011, at 1:19 PM, Michael Cohen wrote:
>
>
>
>
>
>
>
>
>
> > A minor correction...
>
> > Although classes define properties, and PROTOCLASS creates one for each MV file field, you need a instance of a class to reference its properties.
>
> > So MVBasic can open an object corresponding to the record in the example, and reference and set the value of its properties, as:
>
> > p1="MVFILE.PERS"->%OpenId(1)
> > crt p1->Fname
> > p1->Fname="Mary"
> > p1->%Save()
>
> > --
> > You received this message because you are subscribed to the Google Groups "InterSystems:  MV Community" group.
> > To post to this group, send email to Cac...@googlegroups.com
> > To unsubscribe from this group, send email to CacheMV-u...@googlegroups.com
> > For more options, visit this group athttp://groups.google.com/group/CacheMV?hl=en

oZone

unread,
Nov 1, 2011, 5:40:19 PM11/1/11
to InterSystems: MV Community
We are also investigating %Installer to automate certain elements of
our installs.

Bill Farrell

unread,
Nov 1, 2011, 5:45:55 PM11/1/11
to InterSy...@googlegroups.com

On Tue, 2011-11-01 at 14:40 -0700, oZone wrote:
> We are also investigating %Installer to automate certain elements of
> our installs.


Lee, I'd like to see that one covered, too. After you supplied an
example for me it looks pretty straightforward. I'm sure there are
nuances that we all might could put to use.

B

Dawn Wolthuis

unread,
Nov 1, 2011, 6:00:42 PM11/1/11
to intersy...@googlegroups.com
I was laughing before I got to %Awesome (we will request your implementation of that once we are ready) because of your intended use of %WebStress. Let me know how that goes.  Cheers!   --dawn

For more options, visit this group at http://groups.google.com/group/CacheMV?hl=en

oZone

unread,
Nov 1, 2011, 6:10:08 PM11/1/11
to InterSystems: MV Community
I know it's 5 months away, but I hope we have another MV collaboration/
sharing session to talk about these types of things at Global Summit.
It's always fun to rub shoulders with the wacky MV crowd. Some of the
best things we've come back from Global Summit with were a result of
those meetings.

Lee Burstein

unread,
Nov 1, 2011, 10:44:22 PM11/1/11
to intersy...@googlegroups.com
Will do Bill.

For those of you who don't know, I'm also the Product Manager for deployment which includes %Installer. I'll create a series of tips on this.

In the mean time, if any one needs help, please do not hesitate to contact me.

> --
> You received this message because you are subscribed to the Google Groups "InterSystems: MV Community" group.
> To post to this group, send email to Cac...@googlegroups.com
> To unsubscribe from this group, send email to CacheMV-u...@googlegroups.com

> For more options, visit this group at http://groups.google.com/group/CacheMV?hl=en

Reply all
Reply to author
Forward
0 new messages