The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Remedy::ARSTools - Provides an object interface to ARSperl (ARS.pm)

ARSperl (ARS.pm) provides a perl interface to the C API to Remedy's Action Request System (that is a C API for talking to remedy servers). Remedy::ARSTools provides an object interface to the ARSperl library, as well as providing some enhancements, and other goodies.

One of the most onerous things about using ARSperl, is that you are constantly having to translate field names between their 'name' and 'field id'. The field id is a unique integer assigned to each field by the remedy server, to do pretty much anything with the field, you need to know it's field id, and of course humans only know the name of the field. All this really ends up meaning that you are all the time having to load a list of field names and field id numbers from the server. For one thing, this is network intensive for big forms, it's also wastes time, is a big mess in your code and is quite positively annoying. So here's what Remedy::ARSTools does for you:

Using ARSperl, we load the field id's, field names, field lengths, (and a whole bunch of other stuff) about every field in a given form or set of forms. Next, using Data::DumpXML this data is dumped to a config file. When a new Remedy::ARSTools object is created, file is then loaded, giving you all the field data you need to do whatever it is you are going to do. I devised this solution when writing some cgi scripts that needed to talk to remedy. Loading the field map for each table was taking FOREVER, not to mention that the remedy server itself was rather overloaded. Believe me this is WAY faster than pulling the field map from the server repeatedly.

"Ok, but what happens when the field map changes?" Remedy::ARSTools has the capability to regenerate the config file when it encounters problems, if the correct options are set at instantiaton (see method: new). So for instance if you had th correct options set when you created your object, and you requested a field or schema which wasn't in the config, then Remedy::ARSTools would automatically download a new field map from the remedy server and store it back in the specified config file (if there were any changes).

NOTE: (version 0.5) -- hooks have been added to support auto-refresh of the config file as described above. However, auto-refresh has not been enabled. You will still need to refresh the config file manually. Hopefully this will be implemented in the next release. (sorry) --Andrew

To Do:

    write test scripts

Dependencies

Data::DumpXML Version 1.03+
ARS Version 1.72+

SYNOPSIS

use Remedy::ARSTools;

$Remedy = Remedy::ARSTools::new( Server => $server_host_or_ip, User => $username, Pass => $password, ConfigFile => $path_to_and_name_of_config_file ) || die ($Remedy::ARSTools::errstr);

or if you don't have a config file yet

$Remedy = Remedy::ARSTools::new( Server => $server_host_or_ip, User => $username, Pass => $password, ConfigFile => $path_to_and_name_of_config_file, GenerateConfig => 1, Schemas => ['array','of','schemas for', 'the config'] ) || die ($Remedy::ARSTools::errstr);

$ticket_number = $Remedy->CreateTicket( Schema => $schema_to_create_ticket_in, Fields => { 'fieldName1' => "value1", 'fieldName2' => "value2 ...etc } ) || die $Remedy->{'errstr'};

$Remedy->modifyTicket( Ticket => $ticket_number_to_modify, Schema => $schema_in_which_ticket_exists, Fields => { 'fieldName1' => 'newvalue1' ... etc } ) || die $Remedy->{'errstr'};

$Remedy->deleteTicket( Ticket => $ticket_number_to_delete, Schema => $schema_in_which_ticket_exists ) || die $Remedy->{'errstr'};

$results = $Remedy->Query( QBE => $remedy_query_string, Schema => $schema_to_retrieve_results_from, Fields => ['array', 'of', 'fieldNames', 'to', 'retrieve'] ) || die $Remedy->{'errstr'};

$parsed_diary = $Remedy->ParseDiary( Diary => $raw_diary_data_from_database, ) || die $Remedy->{'errstr'};

$Remedy->Destroy();

new

Notes

This is the object constructor. Upon failure, the method will return the undef value, and an error message will be written to $Remedy::ARSTools::errstr. At object creation, we load the specified config file containing the field map, and login to the speicified remedy server.

Synopsis

 $Object = Remedy::ARSTools::New([options]) || die $Remedy::ARSTools::errstr;

Options

Server (required)

The hostname of the remedy server to login to.

Port

This option specifies a TCP port on which to communicate with the specified remedy server. The ARS module handles this by setting $ENV{'ARTCPPORT'}. If you have muliple Remedy::ARSTools objects, then this will still play nice, mostly. I've done this by setting the ENV variable just prior to the ARS operation. If the 'Port' isn't specified then it deletes the ENV variable. SO, multiple objects will play nice on different port numbers as long as you don't try more than one ARS operation at once. This is a really bad kludge. You have been warned: check yo' self before ya wreck yo' self if you need multiple objects and one or more of them need the Port option.

User (required)

The username to use to login to 'Server'

Pass (required)

The passowrd associated with 'User'

ConfigFile (required)

This should be the full path to and name of the file which contains (or will contain) the configuration data for the schemas you will be using. If you need to generate a new config file (that is, the file does not yet exist), be sure to set 'GenerateConfig' to a non-zero value, and to suppliy a list of schemas for which to retrieve information on the the 'Schemas' option.

GenerateConfig (required to generate ConfigFile)

If this option is set to a non-zero value, and the file specified on ConfigFile does not exist, Remedy::ARSTools will attempt to retrieve field data for all the schemas listed onthe 'Schemas' option, and write the data to the file specified on ConfigFile.

Schemas

This should be a refernce to an array containing a list of schemas to retreive field data for and store in the new config file. Make sure to include all the schemas you are likely to use. If this option is left undefined, a list of ALL schemas availabel to the user you login with will be retrieved from the server.

LoginOverride

If this option is set to a non-zero value, then Remedy::ARSTools will not attempt to login to the specified server automatically. Keep in mind that you will have to manually tell Remedy::ARSTools to login via the ARSLogin method if you want to use any methods that talk to the remedy server.

Debug

If this option is set to a non-zero value, then debug information is sent to stdout.

CanDelete

Unless this option is set to a non-zero value, the object created will be incapable of executing the 'DeleteTicket' method. Remember to always keep your weapon on safety, unless there's a good reason not to.

LoadARSConfig

Notes

This method will load the specified config file containing field data. Normally this is called internally durring new to load the specified 'ConfigFile'. However you can call this method externally on a pre-existing object if you need to load new field data. Keep in mind that any existing field data is overwritten by the new data when you use this method.

Synopsis

 $Object->LoadARSConfig([options]) || die $Object->{errstr};

Options

File (required)

The filename of the config file containing field data that you want to load.

ARSLogin

Notes

Login to the specified remedy server. This method is typically called internally in the 'new' method. However it may be called externally if the LoginOverride option is set at object creation.

Synopsis $Object->ARSLogin() || die $Object->{errstr};

Options

none

Destroy

Notes

Log out of the remedy server, and destroy the object. You should call this before exiting any programs which use Remedy::ARSTools.

Synopsis

 $Object->Destroy();

Options

none

CheckFieldLengths

Notes

This method is called internally. You should not need to call it externally, unless you really want to. This checks given field values against the field data from from the config file. First we check to make sure we "know" all of the given fields, that is that all of the given fields appear in the config data. If that's all-good, next we check each given field value against the max length in the config data if any of the given values are too long, then we send an error. Also if there are any enum fields, we check that the given enum is within the range of legal enums given in the config file, if we find any strangeness there we also send an error.

Now, there is something about this method that breaks the rules sort of. If there are no errors found in the given data, then we return undef with a $self->{errstr} of "ok". If there is some sort of other error, like a field being presented which does not exist in the config, then we also return undef but with a differnet $self->{errstr}. If there are errors found in the data we return a string containing a list of all the errors. It's not as confusing as it sounds, check out the Synopsis:

Synopsis

 if ($errors = CheckFieldLengths([options])){
     die $errors;
 }elsif ($self->{errstr} eq "ok"){
     print  "no errors in data\n";
 }else{
     die $self->{errstr};
 }

Options

Fields (required)

This is a hash reference containing field names and values to be checked. Each key of the hash should be the field name, and of course the value for the key should be the value to be tested for that field.

Schema (required)

The name of the schema (also called 'Form' these days) that you want to check the field values against.

CreateTicket

Notes

Create a ticket in the given Schema (aka 'Form') with the given field values.

Synopsis

 $ticket_number = $Object->CreateTicket([options]) || die $Object->{errstr};

Options

Fields (required)

This should be a hash reference containing the field names and field values to be set in the new ticket. You may find it convienient to build the hash reference inline with the function call like this:

 Fields => {'field1' => $value1, 'field2' => $value2 }
Schema (required)
 This should be the name of the Schema (aka 'Form') that you wish to create the ticket in.

ModifyTicket

Notes

Modify the given existing ticket with the given field values.

Synopsis

 $Object->ModifyTicket([options]) || die $Object->{errstr};

Options

Ticket (required)

The existing ticket number (aka 'entry id', 'record number') to modify.

Schema (required)

The schema (aka 'Form') that the given ticket number exists in.

Fields (required)

A hash reference containing field values to place in the given ticket. You may wish to build the hash reference inline with the function call (example in 'CreateTicket').

DeleteTicket

Notes

Delete the given ticket from the given schema. Of course this will only delete tickets if the username you gave in 'New' has permission to delete tickets. As an additional safeguard against disaster, you must set the 'CanDelete' option to a nonzero value in the New command, to create an object capable of deleting tickets. (see 'New').

Synopsis

 $Object->DeleteTicket([options]) || die $Object->{errstr};

Options

Ticket (required)

The ticket number (aka 'entry-id', 'record number') of the ticket you wish to delete.

Schema (required)

The Schema (aka 'Form') in which exists the 'Ticket' you are trying to delete.

Query

Notes

You really shouldn't use this. You should get a read-only database account with select access on the aradmin views, and use something like DBIx::YAWM to query the database directly. Using the ARS layer to query presents a LOT more overhead than directly querying the underlying database. Not only overhead on the machine executing the code, but also on the remedy server itself, impacting the performance for the users using the ARUser tool, who have no choice but to query via the ARS layer. As a matter of policy, I personally will not build any automated processes which query via the ARS layer. The only thing which should query via ARS is ARS itself. By sticking to this policy I have managed to run pretty big and heavily used remedy servers on pretty modest hardware. To sum it up DON'T USE THIS. But, anyhow, you might have to use this, so here it is. If you hose your remedy server ... don't say I didn't tell you. ;-)

Data is returned as a reference to an array of hashes. Each nested hash represents a record returned from the query. Each key in the hash is a (human readable) field name, and of course the associated value is the value of that field.

Synopsis

 $data = $Object->Query([options]) || die $Object->{errstr};

Options

QBE

This is the proprietary 'query string' as you would enter it via the ARUser tool. "QBE" stands for "Query By Example", which is buzzword that Remedy uses to describe it's system of querying in the ARUser GUI tool. The string which is derived from the 'Query By Example' process is generally called a 'QBE String' Hence the name. Basically analagous to a 'where' clause in SQL ... basically.

Schema

The schema (aka 'Form') that you wish to query records from

Fields

An array reference containing a list of field you wish to retrieve from the query. Sort of analagous to 'Select' in an SQL string. You may find it helpful to build the array reference inline with the function call like so:

 Fields => ['field1','field2','field3']
 

RefreshARSConfig

Notes

Generate the data structure containing the field data that you would want to dump via Data::DumpXML to a config file so you could load it later. This is where you would refresh the config if you ever needed to. The field data is loaded directly into the object.

Synopsis

 $Object->RefreshARSConfig([options]) || die $self->{errstr};

Options

Schemas (required)

A list of schemas (aka 'Forms') to retrieve field data for.

ParseDiary

Notes

This is one of those routines that dosen't seem to fit in anywhere perfectly. I included it in Remedy::ARSTools, because ... well, it's dern handy, and this seemd to be as good of a place as any for it. If you took my advice from the notes on 'Query' and decided to do your queries directly from the database used by your remedy server, then you might run into some problems with diaries. Remedy stores the diary as one big ol' text field. Which is a problem, because as you are probably aware, the diary has a timestamp and user associated with each entry. So what you get when you select a diary field from your database, is each diary entry separated by some trash. This 'trash' is the username and timestamp. So what this does is to parse a raw diary format into the same format as you would get if you had queried a diary field via ARS (i.e. the same format as returned by ARS::getField.). That format is an array reference. Each element in the array is, in turn, a hash reference. Each nested hash contains three fields 'timestamp', 'user', and 'value'. Oh yeah, and the Array is sorted chronologically, with the earliest entries first. Here's another look at what the data-structure looks like:

\@DIARY = [ { 'timestamp' => $date, 'user' => $user, 'value' => $diary_entry } ... ];

Synopsis

$data = $Object->ParseDiary([options]) || die $Object->{errstr};

Options

Diary (required)

A string containing the raw diary data from the database.

ParseDBDiary

Notes

Ok so if you want to use ParseDiary, but don't want to create an object, you can use this procedural method. This does the same thing as ParseDiary, except you don't need to call it on an object.

Synopsis

$data = Remedy::ARSTools::ParseDBDiary([options]) || die $Remedy::ARSTools::errstr;

Diary (required)

A string containing the raw diary data from the database.

RefreshConfig

Notes

This method is usually called internally, when data is requested which isn't in the config file. You remember, the one I was talking about way back at the top of the doc, that holds all the field data. Yeah, THAT one. ;-) Anyhow, you can call it too if you want. What this does, is to pull all of the field data again from the remedy server, and compare it to the data we already have. If the data is different, we use the new data and also stash it in the config file for next time.

Synopsis

$Object->RefreshConfig([options]) || die $Object->{errstr};

Options

WriteFile

if this option is set to a non-zero value than new data is written back to ConfigFile if it differs from the existing data. If this is not set, then the new data used, but but not updated in ConfigFile

GenerateConfig

Notes

This is another method you won't probably have the opportunity or need to use, as it is called internally. When the file specified on ConfigFile at object instantiation does not exist, and 'GenerateConfig' is set to a non-zero value, this is the bit that goes and fetches the field data for all the schemas specified on the 'Schemas' option and stashes it in the ConfigFile. Don't worry about this, if you need to make a new config file the easiest thing to do is just to call new as described above, or if you don't want to create an object, you could use GenerateARSConfig. What is that? You say you want to know all about it anyhow? Well here you go mucacho, or muchacha:

Synopsis

$Object->GenerateConfig([options]) || die $Object->{errstr};

Options

Server

same as new. the server or ip to connect to. if this is left null, then we use the value from the current object.

User

same as new. the user to connect as. if this is left null, then we use the value from the current object.

Pass

same as new. password for User. if this is left null, then we use the value from the current object.

ConfigFile

the file to write the config data to. if this is left null, then we use the value from the current object.

Schemas

array reference containing list of schemas to retreive data for. if this is left null, then we use the value from the current object.

Port

same as new. port to connect to server on. if this is left null, then we use the value from the current object.

GenerateARSConfig

Notes

Ok, so for some reason, you would like to create a config file for a given set of schemas on a remedy server, but you don't want to be bothered with needing to create an object and all that stuff. You just want to login, get the info, dump it, and move on. Well then, you can just use this procedural method instead!

Synopsis

Remedy::ARSTools::GenerateARSConfig([options]) || die $Object->{errstr};

Options

Server (required)

the server hostname or ip to connect to

User (required)

the user to connect as

Pass (required)

the password for User

ConfigFile (required)

the file where you would like to dump said data

Schemas (required)

array reference containing list of schemas to get field data for

Port (optional)

a specific TCP port on which to connect to Server

GetFieldData

Notes

Seeing as how there are SO DERN MANY methods for retrieving field data, I busted the bit that actually does the retreiving into it's own subroutine so that everyone could share. You really don't need to worry about this.

Synopsis

$data = Remedy::ARSTools::GetFieldData([options]) || die $Object->{errstr};

Options

Schemas

the ubiquitous array reference containing a list of schemas from which to retrieve field data.

CTRL

the ARS control token. You would get one of these from ARSLogin.

Continuum Transfunctioner

Notes

It's mystery is only exceeded by it's power.

Author:

Andrew N. Hicox <andrew@hicox.com> http://www.hicox.com