Digital Eagle
Virtual Moving Day!
Well, I finally decided to do it! I got my own website. So, now comes the challenging part of moving it all to the new site.
So, please update your feeds and bookmarks to:
http://psst0101.digitaleagle.net/
And, if you have any suggestions on how I can make it better, please comment. I apologize for the inconvenience.
Tip: Comparing Trace Files
http://psst0101.digitaleagle.net/2011/01/10/tip-comparing-trace-files/
Trace files can give a lot of nice troubleshooting information, sometimes too much. Sometimes, you may have a situation where a problem occurs in one system but not in another. You could run a trace in both systems, but comparing those trace files is difficult. Each line has a timestamp, which will be different in each file.
Here is a trick for getting rid of those timestamps. Here is the source:
sed : Remove first 4 letters in each line
Of course, you need Linux, Unix, or Cygwin for this — something with the sed program. Here is the command:
sed 's/^.\{51\}//g' "mytrace.tracesql" > modtrace.tracesql
For example, here are the first few lines of a trace file:
PSAPPSRV.248 (181) 1-1 10.24.26 Cur#1.248.FSDEV90 RC=0 Dur=0.001000 COM Stmt=SELECT VERSION FROM PSVERSION WHERE OBJECTTYPENAME = 'SYS' PSAPPSRV.248 (181) 1-2 10.24.26 0.003000 Cur#1.248.FSDEV90 RC=0 Dur=0.001000 COM Stmt=SELECT PORTAL_NAME, PORTAL_REFTYPE, PORTAL_OBJNAME FROM PSPRSMDEFN WHERE VERSION > :1 UNION SELECT PORTAL_NAME, PORTAL_REFTYPE, PORTAL_OBJNAME FROM PSPRSMDEL WHERE VERSION > :2 PSAPPSRV.248 (181) 1-3 10.24.26 0.000000 Cur#1.248.FSDEV90 RC=0 Dur=0.000000 Bind-1 type=8 length=4 value=214748355
After running the command, here is what it looks like:
Cur#1.248.FSDEV90 RC=0 Dur=0.001000 COM Stmt=SELECT VERSION FROM PSVERSION WHERE OBJECTTYPENAME = 'SYS' Cur#1.248.FSDEV90 RC=0 Dur=0.001000 COM Stmt=SELECT PORTAL_NAME, PORTAL_REFTYPE, PORTAL_OBJNAME FROM PSPRSMDEFN WHERE VERSION > :1 UNION SELECT PORTAL_NAME, PORTAL_REFTYPE, PORTAL_OBJNAME FROM PSPRSMDEL WHERE VERSION > :2 Cur#1.248.FSDEV90 RC=0 Dur=0.000000 Bind-1 type=8 length=4 value=214748355
Now, you can use a tool like Beyond Compare or Meld to compare the trace files without the timestamp. If you don’t have a compare tool, look here.
Explorations in Component Interface: Handling Component Interface Errors
http://psst0101.digitaleagle.net/2011/01/10/tip-comparing-trace-files/
This is a continuation of the following posts:
The plan this time is to try to see how well we can handle errors. I have been having trouble with some of my production programs crashing when I have taken all the necessary steps to trap and handle the error. So, we’ll see how this goes …
Trying a Single Error
First, let’s change that second parameter in our program to true. This should trigger the part of our code that set’s the birth state to “XX”. Assuming everything works the way it should, we should catch the Invalid Value message and write it to the log file. Then, the program should run to completion showing the Program Completed message from the second step.
Again, see the App Engine test post for instructions on how to run the program. Then, look in the log file generated by the PeopleCode. As we would expect, we see the Invalid Value messages:
Then, if you look in the program’s standard out log, you see the message as well. I think this is a bug in the tools because we did trap the message. If I tell it to only put the message in the message collection, I should be able to do what I want with the message as far as showing it or hiding it:
Keep in mind that we are specifying the collection only option. If we had chosen “2” or “3” for the messages mode, I would expect the “Invalid Value” message in the standard out, but we are specifying “1”:
Multiple UpdatesNow, lets try multiple updates with a single error at the end:
If you want, you can just copy my lines:
updateCI(&emplid, False); updateCI(&emplid, False); updateCI(&emplid, False); updateCI(&emplid, False); updateCI(&emplid, False); updateCI(&emplid, False); updateCI(&emplid, False); updateCI(&emplid, True);
Both logs look just fine:
The key is that it ran to the end of the PeopleCode hence the “End” message, and it ran all the way through Step 2 hence the “Process Complete” message.
Just to be sure, we should try a few different combinations. Maybe one with the error on the second to last one:
updateCI(&emplid, False); updateCI(&emplid, False); updateCI(&emplid, False); updateCI(&emplid, False); updateCI(&emplid, False); updateCI(&emplid, False); updateCI(&emplid, True); updateCI(&emplid, False);
This didn’t cause any problems for me. So, let’s try one in the middle:
updateCI(&emplid, False); updateCI(&emplid, False); updateCI(&emplid, False); updateCI(&emplid, True); updateCI(&emplid, False); updateCI(&emplid, False); updateCI(&emplid, False); updateCI(&emplid, False);
Again, this worked fine for me. So, I wasn’t able to reproduce my problem that I keep seeing in production.
Triggering an “Error()”So far, our examples haven’t actually triggered an error within the Save. Let’s try that.
First, the easiest way I could come up with was to add some code to the SavePreChange of our component. If you open up the Component Interface from your project, you can right click on the Component on the left hand side. Then, if you choose “View Definition”, it will open the Component. Then, you can choose View > PeopleCode and navigate to the SavePreChange.
I added the following PeopleCode to the end of the program:
If PERSON.BIRTHSTATE = "CA" Then; Error ("California is too far West!"); End-If;
Here is what it looks like:
Then, we need to change the state in our code from “XX” to “CA”.
When our updates look like this:
updateCI(&emplid, True);
We get this in the log:
When our updates look like this:
updateCI(&emplid, False); updateCI(&emplid, False); updateCI(&emplid, False); updateCI(&emplid, True); updateCI(&emplid, False); updateCI(&emplid, False); updateCI(&emplid, False); updateCI(&emplid, False);
We get this in the log:
So, still no problem!
FieldChange ErrorOkay, here is one more shot. I removed my PeopleCode from the SavePreChange. Next, I opened the FieldChange on the Birth State and put the PeopleCode in there.
And here is what the log looks like:
Still works right.
ConclusionIn conclusion, my goal was to demonstrate a bug in handling errors. I think I failed because I wasn’t able to reproduce what I am seeing in production.
The problem I am seeing has to do with multiple updates. The order matters, too. We saw one instance where the last update erred, and everything worked fine. Then on the next run, one of the middle updates erred, and the program stopped. The weird part is that it finishes the PeopleCode program rather than stopping at the Save or where the error occurred. Then, it abends the program at the end of that Step rather than finishing the whole App Engine. So, what I was looking for was for it to not show that “Process Complete” message.
If anyone can figure out how to tweak this to reproduce the problem, please let me know. I would love to demonstrate it so that maybe Oracle could try to fix the problem. If nothing else though, maybe someone will find the code examples useful in creating their own programs.
Great Link: VB.Net posting to PeopleSoft
http://psst0101.digitaleagle.net/2011/01/10/tip-comparing-trace-files/
I did some looking into using VB.Net with PeopleSoft. If you are using VB6, you can look at the Excel to CI macros and find out how to post to an iScript, but VB.Net is different. Here are some links that might help:
- Snippet: HTTP Post, POST XML FILE OVER HTTP POST (VB.NET)
- HttpWebResponse.StatusCode Property
- How to use HttpWebRequest to send POST request to another web server?
- Error: This header must be modified using the appropriate property
- HttpWebRequest.GetResponse() throwing 500 error
- how to resolve http error 504 code
Explorations in Component Interface: PeopleCode
http://psst0101.digitaleagle.net/2011/01/10/tip-comparing-trace-files/
This is a continuation of the following posts:
Now, we need to write some code to use the Component Interface. Let’s use the Application Engine program from this step by step post.
Adding a Log Step to the Program
Before we dive into the PeopleCode, we need to add a second step to the program. This step will come in handy for testing how the program works. It will just simply log a message to the standard out file.
I used this SQL to find a message catalog that would work easily:
SELECT * FROM PSMSGCATDEFN WHERE MESSAGE_TEXT = '%1'
Then, I added a new step. First, you select Step 01. Then, you can either use the menu Insert > Step/Action or the toolbar icon. When you get the new step, change the action from SQL to Log Message. Then, set the Message Set to 94 and the Number to 1. For the parameters, enter something like “Process Complete”.
Generating a PeopleCode CI TemplateNow, we are ready to begin adding PeopleCode to Step 01. You can open the PeopleCode by double clicking anywhere in the gray of the PeopleCode action. If you have been following other tutorials, you probably have something in that program. For simplicity’s sake, let’s just delete that and start from scratch. This tutorial will assume you have a blank program at this point.
One of the cool things about Component Interfaces is that you can have Application Designer generate a template PeopleCode program. If you have the component interface in the project, you can just drag it from the development tab of the project list and drop it into the program. This generates a template in the program. You will want to have a blank program here because it will generate a lot of code. Note that this is a template in that you have to make some changes before you can even save it.
For this purpose, you can edit this template if you want, but it would probably be easier to delete the template back out and just type the code that I have written.
Writing the ProgramFirst, we’ll start with some variables. The file variable is to write a special log file with output information. The session variable stores your session and the oBlgPersDtaCi stores the reference to the component interface. The Emplid variable is going to be used to store the ID we want to update.
Local File &fileLog; Local ApiObject &oSession, &oBlgPersDtaCi; Local string &emplid;
Then, we need this function to display any error messages. It basically just loops through the session’s message collection and prints out any messages that were triggered since the last call.
Function errorHandler() Local ApiObject &oPSMessageCollection, &oPSMessage; Local number &i; Local string &sErrMsgSetNum, &sErrMsgNum, &sErrMsgText, &sErrType; &oPSMessageCollection = &oSession.PSMessages; For &i = 1 To &oPSMessageCollection.Count &oPSMessage = &oPSMessageCollection.Item(&i); &sErrMsgSetNum = &oPSMessage.MessageSetNumber; &sErrMsgNum = &oPSMessage.MessageNumber; &sErrMsgText = &oPSMessage.Text; &fileLog.WriteLine(&sErrType | " (" | &sErrMsgSetNum | "," | &sErrMsgNum | ") - " | &sErrMsgText); End-For; rem ***** Delete the Messages from the collection *****; &oPSMessageCollection.DeleteAll(); End-Function;
Then, we’ll start a function so we can update multiple times. The employee parameter is the ID we want to update, and we’ll use the makeError parameter later. We put everything in a Try to attempt to handle errors gracefully.
Function updateCI(&emplid As string, &makeError As boolean) try
Then, we need to tell the tools what to do with the messages. We will tell it to use the collection only in an effort to handle the messages gracefully:
rem ***** Set the PeopleSoft Session Error Message Mode *****; rem ***** 0 - None *****; rem ***** 1 - PSMessage Collection only (default) *****; rem ***** 2 - Message Box only *****; rem ***** 3 - Both collection and message box *****; &oSession.PSMessagesMode = 1;
Then, we need to initialize the component interface. This is simulating the user clicking the link on the menu to go into the component.
rem ***** Get the Component Interface *****; &oBlgPersDtaCi = &oSession.GetCompIntfc(CompIntfc.BLG_PERS_DTA_CI); If &oBlgPersDtaCi = Null Then errorHandler(); throw CreateException(0, 0, "GetCompIntfc failed"); End-If;
Then, we need to set some modes. Setting Interactive Mode to true is like turning off deferred processing. Get History Items is like checking the Include History box on the search page. Edit History is like checking the correction mode on the search page.
rem ***** Set the Component Interface Mode *****; &oBlgPersDtaCi.InteractiveMode = True; &oBlgPersDtaCi.GetHistoryItems = True; &oBlgPersDtaCi.EditHistoryItems = True;
Then, we update the Empl ID field on the search page:
rem ***** Set Component Interface Get/Create Keys *****; &oBlgPersDtaCi.EMPLID = &emplid;
Then, we click the search button. If this fails, that means no rows were returned.
rem ***** Execute Get *****; If Not &oBlgPersDtaCi.Get() Then rem ***** No rows exist for the specified keys.*****; errorHandler(); throw CreateException(0, 0, "Get failed"); End-If;
Then, we should be on the page where we can make changes. To keep things simple, we are going to work with just one single field on the page — the birth state. First, we print the value to the log. Then, we will either set it to XX to generate an invalid value error or we will toggle the state between FL and TX. Finally, we call the error handler to see if we generated any errors.
rem ***** Begin: Get/Set Component Interface Properties *****; rem ***** Get/Set Level 0 Field Properties *****; &fileLog.WriteLine("&oBlgPersDtaCi.BIRTHSTATE = " | &oBlgPersDtaCi.BIRTHSTATE); If &makeError Then; &oBlgPersDtaCi.BIRTHSTATE = "XX"; Else; If &oBlgPersDtaCi.BIRTHSTATE = "TX" Then; &oBlgPersDtaCi.BIRTHSTATE = "FL"; Else; &oBlgPersDtaCi.BIRTHSTATE = "TX"; End-If; End-If; errorHandler(); rem ***** End: Get/Set Component Interface Properties *****;
Then, we save the component:
rem ***** Execute Save *****; If Not &oBlgPersDtaCi.Save() Then; errorHandler(); throw CreateException(0, 0, "Save failed"); End-If;
Then, we cancel. This is like going back to the search page.
rem ***** Execute Cancel *****; If Not &oBlgPersDtaCi.Cancel() Then; errorHandler(); throw CreateException(0, 0, "Cancel failed"); End-If;
Then, we finish up our try, catch and our function.
catch Exception &ex rem Handle the exception; &fileLog.WriteLine(&ex.ToString()); end-try; End-Function;
Now, this is the start of the main part of the program. We will set our Empl ID, open the log file and get the current session:
&emplid = "KU0001"; rem ***** Set the Log File *****; &fileLog = GetFile("C:\temp\BLG_PERS_DTA_CI.log", "w", "a", %FilePath_Absolute); &fileLog.WriteLine("Begin"); rem ***** Get current PeopleSoft Session *****; &oSession = %Session;
Then, we call our function to use the CI:
updateCI(&emplid, False);
Finally, we wrap up the log file.
&fileLog.WriteLine("End"); &fileLog.Close();Full Program
And, here is the full program:
The ResultLocal File &fileLog;Local ApiObject &oSession, &oBlgPersDtaCi;Local string &emplid;Function errorHandler()Local ApiObject &oPSMessageCollection, &oPSMessage;Local number &i;Local string &sErrMsgSetNum, &sErrMsgNum, &sErrMsgText, &sErrType;&oPSMessageCollection = &oSession.PSMessages;For &i = 1 To &oPSMessageCollection.Count&oPSMessage = &oPSMessageCollection.Item(&i);&sErrMsgSetNum = &oPSMessage.MessageSetNumber;&sErrMsgNum = &oPSMessage.MessageNumber;&sErrMsgText = &oPSMessage.Text;&fileLog.WriteLine(&sErrType | " (" | &sErrMsgSetNum | "," | &sErrMsgNum | ") - " | &sErrMsgText);End-For;rem ***** Delete the Messages from the collection *****;&oPSMessageCollection.DeleteAll();End-Function;Function updateCI(&emplid As string, &makeError As boolean)tryrem ***** Set the PeopleSoft Session Error Message Mode *****;rem ***** 0 - None *****;rem ***** 1 - PSMessage Collection only (default) *****;rem ***** 2 - Message Box only *****;rem ***** 3 - Both collection and message box *****;&oSession.PSMessagesMode = 1;rem ***** Get the Component Interface *****;&oBlgPersDtaCi = &oSession.GetCompIntfc(CompIntfc.BLG_PERS_DTA_CI);If &oBlgPersDtaCi = Null ThenerrorHandler();throw CreateException(0, 0, "GetCompIntfc failed");End-If;rem ***** Set the Component Interface Mode *****;&oBlgPersDtaCi.InteractiveMode = True;&oBlgPersDtaCi.GetHistoryItems = True;&oBlgPersDtaCi.EditHistoryItems = True;rem ***** Set Component Interface Get/Create Keys *****;&oBlgPersDtaCi.EMPLID = &emplid;rem ***** Execute Get *****;If Not &oBlgPersDtaCi.Get() Thenrem ***** No rows exist for the specified keys.*****;errorHandler();throw CreateException(0, 0, "Get failed");End-If;rem ***** Begin: Get/Set Component Interface Properties *****;rem ***** Get/Set Level 0 Field Properties *****;&fileLog.WriteLine("&oBlgPersDtaCi.BIRTHSTATE = " | &oBlgPersDtaCi.BIRTHSTATE);If &makeError Then;&oBlgPersDtaCi.BIRTHSTATE = "XX";Else;If &oBlgPersDtaCi.BIRTHSTATE = "TX" Then;&oBlgPersDtaCi.BIRTHSTATE = "FL";Else;&oBlgPersDtaCi.BIRTHSTATE = "TX";End-If;End-If;errorHandler();rem ***** End: Get/Set Component Interface Properties *****;rem ***** Execute Save *****;If Not &oBlgPersDtaCi.Save() Then;errorHandler();throw CreateException(0, 0, "Save failed");End-If;rem ***** Execute Cancel *****;If Not &oBlgPersDtaCi.Cancel() Then;errorHandler();throw CreateException(0, 0, "Cancel failed");End-If;catch Exception &exrem Handle the exception;&fileLog.WriteLine(&ex.ToString());end-try;End-Function;&emplid = "KU0001";rem ***** Set the Log File *****;&fileLog = GetFile("C:\temp\BLG_PERS_DTA_CI.log", "w", "a", %FilePath_Absolute);&fileLog.WriteLine("Begin");rem ***** Get current PeopleSoft Session *****;&oSession = %Session;updateCI(&emplid, False);&fileLog.WriteLine("End");&fileLog.Close();
See the App Engine test post for instructions on how to run the program. If it worked, you should get this in the log file:
The standard out of the program should look like this:
And, the page should have changed the birth state:
Component Interfaces Explorations: Security
http://psst0101.digitaleagle.net/2011/01/10/tip-comparing-trace-files/
This is part two of the explorations in component interfaces. Before we can do anything with the Component Interface that we created in part one, we have to make sure that we have security to it. Maybe at some point we can explore what happens when we don’t have security, but for now let’s fix it before it breaks.
So, if you haven’t already created the component interface, head over to part one first, and build the CI. Then, you can setup the security.
The first thing you must know is which permission list you need to attach to. Normally, your security would decide this. You could create one permission list for all of the component interfaces in the system and grant that to everyone — I mean, the user can’t use the component interface unless they have access to the process or page that uses it. Or, you could attach the component interface to the same permission list that gives the user access to the corresponding page or process.
In this case, we are just going to pick any one of the permission lists we have access to. This is an experiment anyway, not a production thing.
First, open the User Profile for the Operator ID you use to connect — PeopleTools > Security > User Profiles > User Profiles. Go to the Roles tab, and pick any one of the Roles. I am picking the PeopleSoft User role:
Clicking the View Definition link will take you to the Role. Then, click on the Permission Lists page and choose one of the permission lists in the list. In my case, there is only one, so I clicked the View Definition on that one:
Now, that you are on the Permission List, you need to go to the Component Interfaces tab/page. Then, add the component interface name that you created in part one.
If you save at this point, you haven’t done anything. PeopleTools will remove it from the permission list because you haven’t given it any access yet. Make sure that you click the Edit link and click the Full Access button:
Finally, make sure that you click Ok and Save to save the component interface. You may want to re-open that permission list, and make sure that it saved the change.
Now you have security. Stay tuned for writing some code to make it work…
Y2K10 PeopleSoft Style
http://psst0101.digitaleagle.net/2011/01/10/tip-comparing-trace-files/
I was surprised to find today that many of the PeopleTools items on the menu were missing. Then, someone pointed me to article 1183084.1 on Oracle Support.
The problem is that many of the content references have a Expiration Date or Valid To date of 12/31/2010. If you have some patience, you can go though Portal Structure and Content and update each one. But, PeopleSoft has an Application Engine program attached to the article that will automatically do it.
Running the program is pretty straight forward. The only thing I had to do was adjust the last updated field. The program only updates content references that were last updated by PPLSOFT, but most of my content references were marked with PS. You could either update the PSPRSMDEFN table manually in the database, but I changed all of the references for ” = ‘PPLSOFT'” to ” IN (‘PPLSOFT’, ‘PS’)”.
Explorations in Component Interface
http://psst0101.digitaleagle.net/2011/01/04/explorations-in-component-interface/
This is part one of a multi-part series exploring some quirks in using Component Interfaces with Application Engine programs. If nothing else, hopefully, these will give new developers some insight into how to use a Component Interface. My goal is to expose a bug in the Application Engine tool that maybe Oracle will see and fix.
This first part will simply walk you through creating a Component Interface. This part is just a map to associate the fields on the screen (or really in the component’s buffer) with an API property that can be accessed with code.
First, we create a new definition in Application Designer. You can either use the Ctrl + N keyboard shortcut or the File > New menu. Choose Component Interface from the list:
Next, have no fear — you will see the open dialog making it look like you want to open a component. Really, Application Designer is just asking you which component you want to map. In this example, we will use the “PERSONAL_DATA” component, which is the Modify a Person screen (Workforce Administration > Personal Information > Modify a Person):
Next, Application Designer asks you if you want to default the properties. I almost always say yes to this questions because it will make Application Designer do all the work for you in generating the map. The properties will be given names based on their field names in the buffer:
Now, you should have a new component interface generated for you. Notice that the left side is the Component Structure. It is the same as the Structure tab on the Component itself. The right side is the map of record/field to property name. In this screenshot, I have the component open in the background and I drew a line to show how the structure is the same. Then, I drew a line from the structure to the property generated for one of the fields:
Finally, save the component interface. You can either use the Ctrl + S keyboard shortcut, or you can use the File > Save menu. I gave it the name BLG_PERS_DTA_CI.
While your at it, you may also want to add it to the project. You can use the F7 keyboard shortcut or the Insert > Current Definition Into Project menu.
This concludes creating the Component Interface. Please stay tuned for the next steps …
2010 in review
http://psst0101.digitaleagle.net/2011/01/02/2010-in-review/
The stats helper monkeys at WordPress.com mulled over how this blog did in 2010, and here’s a high level summary of its overall blog health:
The Blog-Health-o-Meter™ reads Wow.
Crunchy numbersA helper monkey made this abstract painting, inspired by your stats.
About 3 million people visit the Taj Mahal every year. This blog was viewed about 55,000 times in 2010. If it were the Taj Mahal, it would take about 7 days for that many people to see it.
In 2010, there were 26 new posts, growing the total archive of this blog to 158 posts.
The busiest day of the year was September 22nd with 375 views. The most popular post that day was Step By Step.
Where did they come from?The top referring sites in 2010 were peoplesoft.wikidot.com, jjmpsj.blogspot.com, psinstall.blogspot.com, google.com, and google.co.in.
Some visitors came searching, mostly for ora-01502, peopletools tables, windows file lock viewer, yum samba, and peoplesoft installation step by step.
Attractions in 2010These are the posts and pages that got the most views in 2010.
Step By Step September 2008
11 comments
PeopleTools Tables September 2007
29 comments
ORA-01502: Indexes in unusable state February 2008
6 comments
Server Administration Tip: Logging Into the Weblogic Console March 2007
1 comment
Step by Step: Yum + Samba December 2008
Project Shaphan Updated
http://psst0101.digitaleagle.net/2010/11/27/project-shaphan-updated/
I just finished releasing a new version of my Project Shaphan to the Google Code site. My goal with the project is to create a database query tool. Oracle has SQL Developer which is a great, but it is geared more for database development. Most PeopleSoft database users will never see a line of plsql or a single stored procedure. What we need is a tool that understands PeopleSoft databases more and offers tools for querying it.
New Feature: Navigation Search
It isn’t very pretty, but here is a tool where you can enter a Component Name, and the tool will display all of the navigations for that component:
Meta SQL
I only have %CurrentDateIn working right now, but I plan to get more:
Getting Your Copy
To try it out, you can download the Jar file from the right side of the main page. Make sure you have Java 6 installed. Then, place the Jar file in a directory by itself, and double click on it.