This chapter provides an overview of diagnostic PeopleCode and discusses how to:
Develop diagnostic plug-ins.
Make diagnostic plug-ins available.
Use the PTDiagnostics application class.
PTDiagnostics Class Reference.
PeopleSoft delivers Diagnostics Framework base classes in an application package that can be extended to create your own diagnostic plug-in. Methods in these base classes can be called by application classes in the extended application packages, to return diagnostic information back into Diagnostics Framework.
A diagnostic plug-in can be comprised of a single application class or multiple application classes within the extended application package. Each of the application classes within the plug-in must be extended from the PTDiagnostics base application class.
How Diagnostic Plug-Ins Are Used
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 are instantiated only by Diagnostics Framework, and can't be called from any other location, including PeopleCode programs.
Diagnostic plug-in classes must contain certain methods that are recognized and used by Diagnostics Framework.
This section provides an overview of plug-in structure and discusses how to:
Import the PTDiagnostics class.
Define the IsPlugIn method.
Define the GetDiagnosticInfo method.
Define the GetDynamicPrompt method.
You use the Application Packages editor in PeopleSoft Application Designer to create application packages that are treated as diagnostic plug-ins by the framework.
Each of the application classes within the diagnostic plug-in asks one diagnostic question, and can return multiple answers to that question.
Each application class you define within a diagnostic plug-in must:
Inherit from the delivered PT_DIAGNOSTICS application package by using the following in the import section:
import PT_DIAGNOSTICS:*;
Contain a constructor method that includes the following within the body of the constructor:
%Super = create PTDiagnostics();
Contain a public method called IsPlugIn to identify the class as part of a diagnostic plug-in.
Contain a public method called GetDiagnosticInfo to run the diagnostic.
The application class can also contain an optional public method called GetDynamicPrompt to prompt users for additional information.
Note. You can also define your own private methods within the application class, which you can call only within the class.
See Also
Creating Application Packages and Classes
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 to your program.
An import statement names the application class. The application package PT_DIAGNOSTICS contains the PTDiagnostics class.
The import statement you should use is 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.
See Also
This required public method is invoked by Diagnostics Framework when you register the plug-in, to verify that the class is part of a diagnostic plug-in. You don't need to define the method beyond the following:
method IsPlugIn end-method
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. 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;
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.
Other Considerations for GetDiagnosticInfo
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.
See Also
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. Following is an example of GetDynamicPrompt that prompts users for record names:
method GetDynamicPrompt Local boolean &status; &status = %Super.InsertQuestion("Recs", "Enter Records to search for, beginning with: ", "String", True); end-method;
See Also
This section discusses how to:
Register diagnostic plug-ins.
Insert plug-ins into projects.
Page Name |
Object Name |
Navigation |
Usage |
PT_DIAG_FRAME_REG |
Application Diagnostics, Register Diagnostics |
Register new diagnostic plug-ins. |
Access the Register Diagnostics page.
After you create a new diagnostic package in PeopleSoft Application Designer, define the plug-in by registering the application package on the Register Diagnostics page.
Package Name |
Add a row and select the new plug-in from the drop down list. |
Note. Available values include application packages that are not for diagnostic purposes. If you select an application package that is not specifically written as a diagnostic plug-in, the system returns an error message.
Once the diagnostic plug-ins have been inserted into a project, they can be copied or compared between databases and can be exported to and imported from files, using PeopleSoft Application Designer. This step would be necessary for plug-ins that you might want to send to the PeopleSoft Global Support Center for their review.
To insert a plug-in into a project:
In Application Designer, open the Insert into Project dialog box.
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.
See Also
This PeopleCode application class is part of the PT_DIAGNOSTICS application package. It establishes the basic framework for developing your diagnostic plug-ins. To define your plug-in, you develop a new application package containing one or more application classes that extend the PTDiagnostics application class.
The PTDiagnostics application class contains methods and properties that you can extend to develop your diagnostic plug-ins.
This section discusses the diagnostic methods for the PTDiagnostics PeopleCode class. The methods are listed in alphabetical order.
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.
See Also
Defining the GetDiagnosticInfo Method
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.
See Also
Defining the GetDiagnosticInfo Method
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.
See Also
Defining the GetDynamicPrompt Method
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).
This section lists the properties for the PTDiagnostics PeopleCode class. The properties are listed in alphabetical order.
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
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
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
Defining the GetDynamicPrompt Method
The following are examples of typical actions you might perform using the notification classes.
The following example demonstrates how to return the list of languages in 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;
The following example demonstrates how to return a user's 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;
The following example demonstrates how to return row counts:
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;
The following example demonstrates the use of global prompting.
import PT_DIAGNOSTICS:*; class GetRecordsBeginningWith extends PTDiagnostics /* Constructor */ method GetRecordsBeginningWith(); /* Public Method */ method GetDiagnosticInfo(); method GetDynamicPrompt(); method IsPlugIn(); private end-class; method GetRecordsBeginningWith; Local boolean &status = False; %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 records in your PeopleSoft database that matches the following search criteria. This diagnostic tests globalType prompting."); end-method; method GetDynamicPrompt Local boolean &status; &status = %Super.InsertQuestion("Recs", "Enter Records to search for, beginning with: ", "String", True); 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"); &status = %Super.GetUserInputByKey("Recs", &sVal); &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; end-method; method IsPlugIn end-method;
The following example demonstrates the use of global and class-level prompts.
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;
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;
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;
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;