Handling structures in the Smarts Perl API

I have a PERL question.
In ASL I have the following:
gObj->criteria += list(criteria, string(value));
...  which works.
I want to do the same thing in PERL, but I cannot get it to work.  I have tried just about everything I can think of, and cannot store values in a structure_set.
Here are the properties for the class in question .. (ICF_GroupSelector)
ChildGroup = <relationship>
CreationClassName = <string>
Description = <string>
DisplayName = <string>
Name = <string>
PartOf = <relationship set>
Priority = <unsigned int>
ROpriority = <unsigned int>
SelectedBy = <relationship>
ServiceName = <string>
TargetClass = <string>
criteria = <structure set>
full_criteria = <structure set>
isaCriterion = <string>
My answer
It always surprises me that this question doesn't get asked more often.
The basic problem is that perl's scalar variables are not typed. When you say "$a=10;" perl doesn't remember that you used an integer - but stores the value as BOTH a string AND an integer. This means that the perl API (or any other library) cant tell the difference between 10 and "10".
On the other hand, the Smarts external API is strongly typed and requires that the message exchange to invoke an API call has the data types specified - and that's what the perl API does for you. To help us, the majority of API calls take fixed types, as do the majority of operations. In addition the remote API allows a program to determine what types an operation takes. This means that in the vast majority of cases, the Perl API can determine what types an API call or operation requires, and does the formatting of the messages exchanged accordingly.
The exception to all this is the handling of model structures. These appear to the API as lists of scalars, or lists of lists of scalars - but there is nothing in the Smarts remote API that allows the perl API to know what scalar types the structure is composed of.
One way to solve the problem would be to have domain-specific encoding information as part of the Perl API itself - but that makes it very non-generic.
The pragmatic solution to the problem is to require the programmer to help out.
As of this moment, this means dropping down a level in the API hierarchy, and using the raw primitives.
Here's an example...
use InCharge::session;
my $s = InCharge::session->init();
my $o = $s->object( "ICF_Criteria", "ICF-Criteria-ICS_NL-Default-0" );
my $x = [
      [ [ STRING => "Owner" ], [ STRING => "~SYSTEM" ] ],
      [ [ STRING => "Active" ], [ STRING => "TRUE" ] ]
$s->put_P( $o, "criteria", $x );
The type keywords ("STRING", "ANYVALARRAY_SET", etc) are those listed in the typeCodeTable in "remote.pm".
I have to say that I am not proud of this complexity, but the perl API is restricted to using the information provided by the remote API protocol - so we have to live with it (for now).

Example #2 -- Setting passwords in CLI_AccessSetting objects

A follow-on question I have been asked since writing the above is about setting the encrypted Password field in a CLI_AccessSetting object.
The technique is the same but there is one non-obvious wrinkle to discover which is that although the dmctl "getop" query indicates that a "structure set" is required, in truth it seems that a single structure is needed. It looks to me as if the dmctl output is wrong - but here's the way round that problem.
First, check the dmctl "getprop" output..
Properties of class CLI_AccessSetting:
     AccessProtocol = <string>
     CreationClassName = <string>
     Description = <string>
     DisplayName = <string>
     IsEnabled = <boolean>
     LoginID = <string>
     MetaMemberOf = <relationship set>
     Name = <string>
     PartOf = <relationship set>
     Password = <structure set>
     PrivilegedModePassword = <structure set>
     ServiceName = <string>
     SettingFeature = <string>
     SettingKey = <string>
     TargetClass = <string>
     Timeout = <unsigned int>
     Type = <string>
Having seen this, I experimented to see how to set the password with ASL and eventually found that this works..
START { .. eol } do {
    s = create("CLI_AccessSetting", "SET-CFG-test");
    s->Password = list("onetwothree", "ENCRYPTED");
Which in turn leads us to the perl equivalent of..
use InCharge::session;

my $sess = InCharge::session->init();

my $s = $sess->create("CLI_AccessSetting", "SET-CFG-test");
my $pass = [ ANYVALARRAY => [ [STRING => "onetwothree"], [STRING => "ENCRYPTED"] ] ];

$sess->put_P($s, "Password", $pass);
Scroll to Top