This chapter provides an overview of diagnostic plug-in development and discusses:
Developing Diagnostic Plug-Ins.
Working with the Delivered PT_DIAGNOSTIC Application Package.
PTDiagnostics Application Class.
PTDIagnostics Class Methods.
PTDIagnostics Class Properties.
Diagnostic Plug-In Examples.
Understanding Diagnostic Plug-In Development
A diagnostic plug-in is an application package developed while adhering to the diagnostic plug-in standard. Developers use the application packages editor in Application Designer to create the application packages that are treated as diagnostic plug-ins by the framework.
PeopleTools delivers Diagnostics Framework base classes in an application package called PT_DIAGNOSTICS. To create your own diagnostic plug-in, a new application package needs to be created and extended from the application package PT_DIAGNOSTICS. The new application package can have multiple numbers of application classes which should be extended from the base classes in PTDiagnostics, delivered in the PT_DIAGNOSTICS application package.
The sub classes can call the base class methods to collect the diagnostic information and return the same information to the Diagnostics Framework. Each of the application classes within the diagnostic plug-in focuses one diagnostic area and can return different information, depending on the state of the application and the nature of the 'question'.
The application class also can contain an optional public method, called GetDynamicPrompt, to prompt users for additional information.
The following types of data can be retrieved and displayed in the Diagnostics Framework:
String
Date
Number
Boolean
Rowset
Note. You can also define your own private methods within the application class, which you can call only within the class.
You define diagnostic plug-ins using application classes, but you don't use them in the same way that other PeopleCode application classes are used. Diagnostic plug-in classes:
must be instantiated only by Diagnostics Framework. They can't be called from any other location, including other PeopleCode programs.
must contain three mandatory methods that are recognized and used by Diagnostics Framework.
Note. Developing custom diagnostic plug-ins requires a working knowledge of PeopleCode and application classes.
See Also
Developing Diagnostic Plug-Ins
This section discusses how to:
Create the diagnostic application package.
Create the diagnostic application classes.
Implement the diagnostic PeopleCode.
Register the diagnostic plug-in.
Share diagnostic plug-ins
Note. Except for registering the Diagnostic Plug-in, which is performed using a PIA page, you complete all of these development steps using Application Designer.

Creating the Diagnostic Application PackageTo create a diagnostic application package: Open the application package in Application Designer, Save the package.
In Application Designer select File, New, Application Package.
Save and name the package.
See Application Classes.

Creating the Diagnostic Application ClassesIn the application package you've created, create a new application class, and save the class.
Note. You can pass only one data type in each diagnostic plug-in application class. To return multiple data types, define multiple application classes. Results that are passed to the framework are retained in memory.
See Application Classes.

Implementing the Diagnostic PeopleCodeTo implement the diagnostic PeopleCode:
Open the PeopleCode editor (View, PeopleCode).
Import the PTDiagnostic package, by entering:
import PT_DIAGNOSTICS:*;
This imports all the classes in the PT_DIAGNOSTICS application package.
Define the class, using the same procedure as your would for any PeopleCode program. For example,
class <class name> extends PTDiagnostic:PTDiagnostic
This makes the class a diagnostic application class.
The class name mentioned in the PeopleCode should be the same as the class name which is under the application package.
All the classes defined in the diagnostic plug-in application package should be extended from the class PTDiagnostic:PTDiagnostic.
Define the following mandatory methods:
|
Method |
Description |
|
Method <class name> |
This is the constructor of the class. Inside the method it is mandatory to have%Super = create PT_DIAGNOSTICS:PTDiagnostics(). More description of %Super resides in the PTDiagnostics application class. If you want to display the rowset in the browser, then you have to set the hasRowset property to True, otherwise make it False. For example, &status = %Super.SetProperty (%This, "hasRowset", "Boolean", False); If you want to call additional information from the user during the execution and use it as the search criteria, then set the Where property to true, otherwise make it False. For example, &status = %Super.SetProperty (%This, "Where", "Boolean", True); |
|
Method GetDiagnosticInfo |
This is the method that gets called when you launch the diagnostic plug-in. To display any output in the browser you have to call %Super.Insertdata(Data type, <String to name the display>, <variable name>). |
|
Method IsPlugIn |
The purpose of this method is to identify the application package as a diagnostic plug-in. If this method is not present, then the system does not recognize it as a diagnostic plug-in during the registration process. This method should appear at the end of the diagnostic application class, and it should be an empty method. The definition of this should be : Method IsPlugIn end-method; |

Registering the Diagnostic Plug-InBefore a diagnostics application package can be used, you have to register it using the Register Diagnostics page. Once the registration is complete, the application package becomes a diagnostic plug-in.
To register a diagnostic plug-in:
Access the Register Diagnostics page by selecting Application Diagnostics, Register Diagnostics.
Add a row, if needed.
In the Plug-In Name edit box, enter the name of the application package, or use the lookup prompt to select it.
Note. When using the lookup prompt, the system displays all application packages not only diagnostic plug-in packages. When developing custom diagnostic plug-ins, using a naming convention can be helpful to refine the search.
Click Save.
Note. If you have not defined the IsPlugIn method or if it is not at the end of the class, an error message appears. The system only registers application packages containing all the required elements of a diagnostic plug-in.

Sharing Diagnostic DefinitionsOnce the registration is complete, the application package can be selected as a Diagnostic Plug-In in Application Designer. Inserting diagnostic plug-ins into projects, enables them to be shared, copied to or compared between databases, and exported to and imported from files. Sharing diagnostic plug-ins would be necessary for plug-ins that need to be sent to Oracle support staff for their review, for example, or to other developers at your site.
The project should contain the:
Diagnostic plug-in
application package
application package PeopleCode
To insert a plug-in into a project:
In Application Designer, select Insert, Definitions into Project.
Select Diagnostic Plug-Ins as the definition type.
Select the plug-in and click Insert.
After inserting the plug-in, make sure to include the underlying application packages and application package PeopleCode in the project as well.
Once the diagnostic plug-in definitions have been inserted into a project, you can share a diagnostic plug-in. Check the Upgrade tab to see these definition types: Application Packages, Diagnostic Plug-Ins, and PeopleCode. You cannot see these with the Development tab selected.
To share a diagnostic plug-in:
Open the project containing the diagnostic definitions in Application Designer.
Select Tools, Copy Project, to File.
Share the generated XML file with the interested parties.
See Also
Working With The Delivered PT_DIAGNOSTIC Application PackagePeopleTools delivers the PT_DIAGNOSTIC application package as part of the Diagnostics Framework. This package is the base package and its classes are base classes for the diagnostic plug-in.
To define a new plug-in, create a new application package, containing one or more application classes that imports the PT_DIAGNOSTIC application package.
When working with the PT_DIAGNOSTIC application package, make sure you understand:
PTDiagnostics Application Class
PTDiagnostics Class Methods
PTDiagnostics Class Properties
These elements are described in the following sections.
PTDiagnostics Application Class
The PTDiagnostics application class is part of the PT_DIAGNOSTICS application package. It establishes the basic framework for developing the diagnostic plug-ins. The PTDiagnostics application class contains methods and properties that you can extend to develop your diagnostic plug-ins. The PTDiagnostics Class is not a built-in class, like Rowset, Field, Record, and so on. It's an application class.
Before you can use this class in your PeopleCode program, you must import it into your program, using an import statement. The application package PT_DIAGNOSTICS contains the PTDiagnostics class. The import statement should be as follows:
import PT_DIAGNOSTICS:*;
Using the asterisk (*) after the package name makes all the application classes directly contained in the named package available. Application classes contained in subpackages of the named package are not made available.
In the constructor of the application class which extends the PTDiagnostics class you need to instantiate the PTDiagnostics class. The extended application classes collect the information whenever required and pass it to the super class, which is the PTDiagnostics class. You instantiate this class as:
%Super = create PT_DIAGNOSTICS:PTDiagnostics()
PTDiagnostics Class Methods
This section discusses the diagnostic methods for the PTDiagnostics PeopleCode class. The methods are listed in alphabetical order.

GetDiagnosticInfoDescription
Use this required public method to define the code that retrieves diagnostic information and returns it to Diagnostics Framework for presentation to the user. This method is invoked by Diagnostics Framework to initiate information collection, then output the results.
The GetDiagnosticInfo method uses the base class InsertData method to pass the results of the diagnostic to Diagnostics Framework for presentation to the users, for example:
&status = %Super.InsertData("Number", "Number of Records: ", &rs1.RowCount);
InsertData can pass output data using the following data types:
String
Number
Date
Boolean
Rowset
Before you can pass rowset data as output, you must first use the base class SetProperty method to set the base class hasRowset property to True.
Considerations for GetDiagnosticInfo include:
You can pass only one data type in each diagnostic plug-in application class. To return multiple data types, define multiple application classes. Results that are passed to the framework are retained in memory.
If you're also defining the GetDynamicPrompt method to prompt users for additional information, use the base class GetUserInputByKey method to retrieve the user responses, for example:
&status = %Super.GetUserInputByKey("Recs", &sVal);
For more readable output, use the base class SetProperty method to insert a description into the base class Purpose property, for example:
&status = %Super.SetProperty(%This, "Purpose", "String", "This is a diagnostic to determine your license code.");
Note. You can also set the Purpose property in the constructor or in the GetDynamicPrompt method.
Example
Following is an example of GetDiagnosticInfo that passes rowset data as output:
method GetDiagnosticInfo Local boolean &status; Local number &rc1; Local Rowset &rs1; Local string &sError; &rs1 = CreateRowset(Record.PSLANGUAGES); &rc1 = &rs1.Fill(); &status = %Super.SetProperty(%This, "hasRowset", "Boolean", True); &status = %Super.InsertData("Rowset", "LANGUAGES description, not used in output", &rs1); end-method;

GetDynamicPromptDescription
If you want a diagnostic application class to prompt users for additional information that you can use as dynamic criteria for the diagnostic, you must define a public method called GetDynamicPrompt within the class.
Before you can use the GetDynamicPrompt method, you must first use the base class SetProperty method within the constructor to set the base class Where property to True , for example:
&status = %Super.SetProperty(%This, "Where", "Boolean", True);
Note. If the Where property is
False, Diagnostics Framework ignores the GetDynamicPrompt method.
Within the GetDynamicPrompt method, use the base class InsertQuestion
method to define the questions used to prompt the users.
Example
method GetDynamicPrompt Local boolean &status; &status = %Super.InsertQuestion("Recs", "Enter Records to search for, beginning with: ", "String", True); end-method;

GetUserInputByKey
Syntax
GetUserInputByKey(sKeyID, &data)
Description
The GetUserInputByKey method retrieves the user response to a question, which can then be used as an input parameter in the diagnostic. You invoke this method within the GetDiagnosticInfo method.
Parameters
|
sKeyID |
Specify as a string the key that identifies the question for which you're retrieving the user response. |
|
&data |
Provide a variable to contain the retrieved user response. |
Returns
A Boolean value: True if the user response was retrieved successfully, False otherwise.

InsertData
Syntax
InsertData(propFormat, propDescr, &data)
Description
The InsertData method passes data to Diagnostics Framework to be presented as the output of the diagnostic. This enables you to pass any information you want without having to hardcode base class methods in the plug-in. You invoke this method within the GetDiagnosticInfo method.
Parameters
|
propFormat |
Specify as a string the data type of the data to be presented. Select from the following:
|
|
propDescr |
Specify a string of text to describe or introduce the output data. |
|
&data |
Provide the output data value, in a variable of the data type specified by the propFormat parameter. |
Returns
A Boolean value: True if the data has been inserted into Diagnostics Framework, False if the data can't be inserted into the framework, or if the data type specified by propFormat doesn't exist in the current framework.

InsertQuestion
Syntax
InsertQuestion(sKeyID, sQuestion, sType, GblBool)
Description
The InsertQuestion method passes a question to Diagnostics Framework, which then presents it to the user to obtain an input parameter. You invoke this method within the GetDynamicPrompt method.
Parameters
|
sKeyID |
Specify as a string a key to identify the question. This value must be unique across all plug-ins that are made available to a user. |
|
sQuestion |
Specify as a string the question you want the user to answer. |
|
sType |
Specify as a string the data type of the response required from the user. Select from the following:
|
|
GblBool |
Specify a Boolean value indicating the scope of the question:
Global questions are asked once per plug-in on the Additional Information prompt page. For example, a plug-in could be defined to gather employee information. The plug-in might contain many application classes that gather specific information (for example, one application class for getting employee paycheck information, and one application class for getting employee addresses). Class level questions are asked only for the current application class. For example, for the paycheck information, you might want to prompt for specific pay periods and for the address information, you might want to prompt for an effective date. |
Returns
A Boolean value: True if the method is successful, False otherwise.

IsPlugInDescription
This required public method is invoked by Diagnostics Framework when you register the plug-in. It verifies that the class is part of a diagnostic plug-in. If it is not present, the system will not register the plug-in.
IsPlugIn should be:
at the end of the Diagnostic Application Class.
an empty method.
Example
method IsPlugIn end-method

SetProperty
Syntax
SetProperty(&obj, propName, propFormat, &propValue)
Description
The SetProperty method sets a property of an instantiated PTDiagnostics object to the value that you specify.
Parameters
|
&obj |
Specify the PTDiagnostics object for which you want to set a property. Typically, you'll specify %This. |
|
propName |
Specify as a string the name of the property that you want to set. The values are:
|
|
propFormat |
Specify as a string the data type of the property that you want to set. For hasRowset and Where, specify Boolean. For Purpose, specify string. |
|
&propValue |
Provide the property value, in a variable that has the data type specified by the propFormat parameter. |
Returns
A Boolean value: True if the property specified by propName exists and can be set in the base class, False if the property can't be set (for example, if the current plug-in is used in a previous release of Diagnostics Framework where that property isn't defined).
PTDiagnostics Class Properties
This section lists the properties for the PTDiagnostics PeopleCode class. The properties are listed in alphabetical order.

hasRowset
Description
Use the hasRowset property to indicate whether the InsertData method passes output data to Diagnostics Framework as a rowset. This property only needs to be defined for classes that use rowsets. This property takes a Boolean value:
True: InsertData will pass data in rowset format.
False: InsertData will pass data in string, number, date, or Boolean format. This is the default value.
Note. You must use the SetProperty method to set the value of this property.
See Also

Purpose
Description
Use the Purpose property to specify as a string the text that introduces and describes the purpose of the diagnostic that this application class performs. This text will be displayed as part of the diagnostic output.
The default value of this property is Unknown.
Note. You must use the SetProperty method to set the value of this property.
See Also

Where
Description
Use the Where property to indicate whether this application class should dynamically prompt the user for relevant parameters. This property only needs to be defined for classes that prompt the user.
This property takes a Boolean value:
True: The application class should dynamically prompt the user.
False: The application class should not dynamically prompt the user. This is the default value.
Note. You must use the SetProperty method to set the value of this property, and you must set it from within the constructor method. If you set this property to True, you must define the GetDynamicPrompt method in your application class to prompt the user.
See Also
Diagnostic Plug-In Examples
The following are examples of typical actions found in diagnostic plug-ins. Examples include:
Rowset-Based Output.
String-based output.
Number-based output.
Prompting for global information input.
Prompting for global and class-level information input.
Joining two records.
Handling constructor failure.
Handling InsertData method failure.
Handling dynamic prompting failure.

Example: Rowset-Based Output
The following example demonstrates how to retrieve record output and display it. In this case, the plug-in retrieves the list of languages from the database.
import PT_DIAGNOSTICS:*; class GetLanguages extends PTDiagnostics /* Constructor */ method GetLanguages(); /* Public Method */ method GetDiagnosticInfo(); method IsPlugIn(); private end-class; method GetLanguages; Local boolean &status; %Super = create PTDiagnostics(); &status = %Super.SetProperty(%This, "hasRowset", "Boolean", True); &status = %Super.SetProperty(%This, "Purpose", "String", "This is a diagnostic to determine all of the languages installed in your PeopleSoft Database."); end-method; method GetDiagnosticInfo Local boolean &stat; Local number &rc1; Local Rowset &rs1; Local string &sError; &rs1 = CreateRowset(Record.PSLANGUAGES); &rc1 = &rs1.Fill(); &stat = %Super.InsertData("Rowset", "LANGUAGES description, not used in output", &rs1); end-method; method IsPlugIn end-method;

Example: String-Based Output
This example demonstrates how to retrieve string-based output and display it. In this case, the plug-in retrieves the license code.
import PT_DIAGNOSTICS:*; class GetLicenseCode extends PTDiagnostics /* Constructor */ method GetLicenseCode(); /* Public Method */ method GetDiagnosticInfo(); method IsPlugIn(); private end-class; method GetLicenseCode; Local boolean &status; Local string &sError; %Super = create PTDiagnostics(); &status = %Super.SetProperty(%This, "Purpose", "String", "This is a diagnostic to determine your license code"); end-method; method GetDiagnosticInfo Local string &sLicenseCode, &sLicenseGroup; Local boolean &status; Local string &sError; SQLExec("SELECT LICENSE_CODE, LICENSE_GROUP FROM PSOPTIONS", &sLicenseCode, &sLicenseGroup); &status = %Super.InsertData("String", "Your License Code is: ", Upper(&sLicenseCode)); end-method; method IsPlugIn end-method;

Example: Number-Based Output
This example demonstrates how to retrieve a Number type output and display it. In this case, we retrieve the number of rows from the PSRECDEFN based on different conditions.
import PT_DIAGNOSTICS:*; class GetPSRECDEFNCount extends PTDiagnostics /* Constructor */ method GetPSRECDEFNCount(); /* Public Method */ method GetDiagnosticInfo(); method IsPlugIn(); private end-class; method GetPSRECDEFNCount; Local boolean &status; Local string &sError; %Super = create PTDiagnostics(); &status = %Super.SetProperty(%This, "Purpose", "String", "This is a diagnostic to count the number of records, views, derived work records, and sub-records in your PeopleSoft Database."); end-method; method GetDiagnosticInfo Local boolean &status; Local number &rc1; Local Rowset &rs1; Local string &sError; &rs1 = CreateRowset(Record.PSRECDEFN); &rc1 = &rs1.Fill("where RECTYPE = 0"); &status = %Super.InsertData("Number", "Number of Records: ", &rs1.RowCount); &rs1 = CreateRowset(Record.PSRECDEFN); &rc1 = &rs1.Fill("where RECTYPE = 1"); &status = %Super.InsertData("Number", "Number of Views: ", &rs1.RowCount); &rs1 = CreateRowset(Record.PSRECDEFN); &rc1 = &rs1.Fill("where RECTYPE = 2"); &status = %Super.InsertData("Number", "Number of Derived/Work Records: ", &rs1.RowCount); &rs1 = CreateRowset(Record.PSRECDEFN); &rc1 = &rs1.Fill("where RECTYPE = 3"); &status = %Super.InsertData("Number", "Number of sub-records: ", &rs1.RowCount); end-method; method IsPlugIn end-method;

Example: Prompting for Global Information Input
This example demonstrates how to use global prompting. This example includes the use of these constructs:
GetDynamicPrompt (): This function prompts for the input.
InsertQuestion (): Inserts a question.
GetUserInputByKey (): Gathers the input.
In this example, the plug-in retrieves the number of rows from the PSRECDEFN based on different records. The search record is usually retrieved from the user during runtime.
import PT_DIAGNOSTICS:*; class GetRecFieldsBeginningWith extends PTDiagnostics /* Constructor */ method GetRecFieldsBeginningWith(); /* Public Method */ method GetDiagnosticInfo(); method GetDynamicPrompt(); method IsPlugIn(); private end-class; method GetRecFieldsBeginningWith; Local boolean &status; %Super = create PTDiagnostics(); &status = %Super.SetProperty(%This, "Where", "Boolean", True); &status = %Super.SetProperty(%This, "Purpose", "String", "This is a diagnostic to print out a listing of fields from records in your PeopleSoft database that matches search criteria. This diagnostic tests globalType and classType prompting. The global prompt is retrieved from inputs defined by a different class in this plug-in."); end-method; method GetDynamicPrompt Local boolean &status; Local string &sError; /* define prompt for this class */ &status = %Super.InsertQuestion("Flds", "Enter FieldNames to retrieve, beginning with:", "String", False); end-method; method GetDiagnosticInfo Local boolean &status; Local string &sValRecs, &sValFlds, &sError; Local number &iCount = 0; Local Record &REC; Local boolean &bReturn; Local SQL &SQL1; &REC = CreateRecord(Record.PSRECFIELD); &SQL1 = CreateSQL("%SelectAll(:1) where RECNAME LIKE :2 and FIELDNAME LIKE :3"); /* get global prompt */ &status = %Super.GetUserInputByKey("Recs", &sValRecs); /* get class prompt */ &status = %Super.GetUserInputByKey("Flds", &sValFlds); &SQL1.Execute(&REC, Upper(&sValRecs | "%"), Upper(&sValFlds | "%")); While &SQL1.Fetch(&REC) &iCount = &iCount + 1; &status = %Super.InsertData("String", "Record: " | &REC.RECNAME.Value | " has the following field that matches your criteria: ", &REC.FIELDNAME.Value); End-While; end-method; method IsPlugIn end-method;

Example: Prompting for Global and Class-Level Information Input
The following example demonstrates the use of global and class-level prompts.
import PT_DIAGNOSTICS:*; class GetRecFieldsBeginningWith extends PT_DIAGNOSTICS:PTDiagnostics /* Constructor */ method GetRecFieldsBeginningWith(); /* Public Method */ method GetDiagnosticInfo(); method GetDynamicPrompt(); method IsPlugIn(); private end-class; method GetRecFieldsBeginningWith; Local boolean &status; %Super = create PT_DIAGNOSTICS:PTDiagnostics(); &status = %Super.SetProperty(%This, "Where", "Boolean", True); &status = %Super.SetProperty(%This, "Purpose", "String", "This is a diagnostic to print out a listing of fields from records in your PeopleSoft database that matches search criteria. This diagnostic tests globalType and classType prompting. The global prompt is retrieved from inputs defined by a different class in this plug-in."); end-method; method GetDynamicPrompt Local boolean &status; Local string &sError; /* define the global prompt*/ &status = %Super.InsertQuestion("Recs", "Enter RecordNames to retrieve, beginning with:", "String", True); /* define prompt for this class */ &status = %Super.InsertQuestion("Flds", "Enter FieldNames to retrieve, beginning with:", "String", False); end-method; method GetDiagnosticInfo Local boolean &status; Local string &sValRecs, &sValFlds, &sError; Local number &iCount = 0; Local Record &REC; Local boolean &bReturn; Local SQL &SQL1; &REC = CreateRecord(Record.PSRECFIELD); &SQL1 = CreateSQL("%SelectAll(:1) where RECNAME LIKE :2 and FIELDNAME LIKE :3"); /* get global prompt */ &status = %Super.GetUserInputByKey("Recs", &sValRecs); /* get class prompt */ &status = %Super.GetUserInputByKey("Flds", &sValFlds); &SQL1.Execute(&REC, Upper(&sValRecs | "%"), Upper(&sValFlds | "%")); While &SQL1.Fetch(&REC) &iCount = &iCount + 1; &status = %Super.InsertData("String", "Record: " | &REC.RECNAME.Value | " has the following field that matches your criteria: ", &REC.FIELDNAME.Value); End-While; end-method; method IsPlugIn end-method;
If you only need to define the class level prompt, use only the second InsertQuestion() method in the GetDynamicPrompt() method and one GetUserInputByKey().
If the message is not required during the dynamic input, then pass an empty string in the second parameter of the InsertQuestion() method.

Example: Joining Two RecordsThis example demonstrates the join between two records. This join can be done by creating a view also.
In this example, the plug-in retrieves the objects from the PSLOCK and PSVERSION tables where versions of the objects don’t match.
import PT_DIAGNOSTICS:*; class MatchVersions extends PT_DIAGNOSTICS:PTDiagnostics /* Constructor */ method MatchVersions(); /* Public Method */ method GetDiagnosticInfo(); method IsPlugIn(); private end-class; method MatchVersions; Local boolean &status = False; %Super = create PT_DIAGNOSTICS:PTDiagnostics(); &status = %Super.SetProperty(%This, "Purpose", "String", "This is to retrieve the objects whose versions doesnot match in PSLOCK and PSVERSIONS."); end-method; method GetDiagnosticInfo Local boolean &status; Local Rowset &rs1; Local Rowset &rs2; Local integer &i, &j; Local Row &ro1; &rs1 = CreateRowset(Record.PSVERSION); &rs1.Fill(); &rs2 = CreateRowset(Record.PSLOCK); &rs2.Fill(); For &i = 1 To &rs1.RowCount For &j = 1 To &rs2.RowCount If (&rs1.GetRow(&i).GetRecord(Record.PSVERSION).OBJECTTYPENAME.Value = &rs2.GetRow(&j).GetRecord(Record.PSLOCK).OBJECTTYPENAME.Value) And (&rs1.GetRow(&i).GetRecord(Record.PSVERSION).VERSION.Value <> &rs2.GetRow(&j).GetRecord(Record.PSLOCK).VERSION.Value) Then &status = %Super.InsertData("String", "OBJECTTYPENAME: ", &rs1.GetRow (&i).GetRecord(Record.PSVERSION).OBJECTTYPENAME.Value | " PSVERSION.VERSION: " | &rs1.GetRow(&i).GetRecord(Record.PSVERSION).VERSION.Value | " PSLOCK.VERSION: " | &rs2.GetRow(&j).GetRecord(Record.PSLOCK).VERSION.Value); End-If; End-For; End-For; end-method; method IsPlugIn end-method;

Example: Handling Constructor Failure
The following example demonstrates error handling when the constructor fails.
import PT_DIAGNOSTICS:*; class TestFailedConstructor extends PTDiagnostics /* Constructor */ method TestFailedConstructor(); /* Public Method */ method GetDiagnosticInfo(); method IsPlugIn(); private instance boolean &constructorFailed; end-class; method TestFailedConstructor Local boolean &status; Local string &sError; %Super = create PTDiagnostics(); &status = %Super.SetProperty(%This, "Purpose", "String", "This is a diagnostic to show how developers can trap a failure in the constructor and print out results to the web page."); /* introduce unknown propName of Where1 rather than Where */ &status = %Super.SetProperty(%This, "Where1", "Boolean", True); If Not &status Then %This.constructorFailed = True; Else %This.constructorFailed = False; End-If; end-method; method GetDiagnosticInfo Local string &sError, &sLicenseCode, &sLicenseGroup; Local boolean &status; If %This.constructorFailed Then &status = %Super.InsertData("String", "Status Failed!", "This message will be printed out in the HTML page if something fails in the constructor. This is expected behaviour."); Else SQLExec("SELECT LICENSE_CODE, LICENSE_GROUP FROM PSOPTIONS", &sLicenseCode, &sLicenseGroup); &status = %Super.InsertData("String", "Your License Code is: ", Upper(&sLicenseCode)); End-If; end-method; method IsPlugIn end-method;

Example: Handling InsertData Method Failure
The following example demonstrates error handling when InsertData fails.
import PT_DIAGNOSTICS:*; class TestFailedGetDiagnosticInfo extends PTDiagnostics /* Constructor */ method TestFailedGetDiagnosticInfo(); /* Public Method */ method GetDiagnosticInfo(); method IsPlugIn(); private end-class; method TestFailedGetDiagnosticInfo; Local boolean &status; %Super = create PTDiagnostics(); &status = %Super.SetProperty(%This, "Purpose", "String", "This is a diagnostic to show how developers can trap a failure in GetDiagnosticInfo method and print out results to the web page."); end-method; method GetDiagnosticInfo Local string &sError, &sLicenseCode, &sLicenseGroup; Local boolean &status; SQLExec("SELECT LICENSE_CODE, LICENSE_GROUP FROM PSOPTIONS", &sLicenseCode, &sLicenseGroup); /* introduce unknown propFormat of String1 */ &status = %Super.InsertData("String1", "Your License Code is: ", Upper(&sLicenseCode)); If Not &status Then &status = %Super.InsertData("String", "Status Failed!", "This message will be printed out in the HTML page if something fails here. This is expected behaviour."); End-If; end-method; method IsPlugIn end-method;

Example: Handling Dynamic Prompting Failure
The following example demonstrates error handling when retrieving user prompts.
import PT_DIAGNOSTICS:*; class TestFailedGetUserInputByKey extends PTDiagnostics /* Constructor */ method TestFailedGetUserInputByKey(); /* Public Method */ method GetDiagnosticInfo(); method IsPlugIn(); private end-class; method TestFailedGetUserInputByKey; Local boolean &status = False; %Super = create PTDiagnostics(); &status = %Super.SetProperty(%This, "Purpose", "String", "This is a diagnostic to test getting a 'False' from GetUserInputByKey."); end-method; method GetDiagnosticInfo Local boolean &status = False; Local string &sVal, &sError; Local number &iCount = 0; Local Record &REC; Local SQL &SQL1; &REC = CreateRecord(Record.PSRECDEFN); &SQL1 = CreateSQL("%SelectAll(:1) where RECNAME LIKE :2"); /* sKeyID "Recs" has already be defined elsewhere in the package see if we can get RecJY. should get a False */ &status = %Super.GetUserInputByKey("RecsJY", &sVal); If &status Then &SQL1.Execute(&REC, Upper(&sVal | "%")); While &SQL1.Fetch(&REC) &iCount = &iCount + 1; &status = %Super.InsertData("String", "Record #" | &iCount, &REC.RECNAME.Value | " (" | &REC.RECDESCR.Value | ")"); End-While; Else &status = %Super.InsertData("String", "Status Failed!", "Failed status encountered in retrieving RecsJY key. This is expected behaviour."); End-If end-method; method IsPlugIn end-method;