Exceptional Pro/INTRALINK Scriptingand How to Avoid It
By Marc Mettes
If you've attempted any complex Pro/INTRALINK scripting applications, you're already aware that if a result is not expected, the whole script stops. Examples of this behavior are the message box that appears after running a BOM report on an empty assembly, a family table report on a non-family table object, or a relationship report on an object with no relationships.
The good news is that these "error" messages are actually unhandled Java exceptions. If your script properly handles these exceptions, it can continueallowing it to make important decisions about what to do next at runtime.
Handling the Exceptions
To handle exceptions thrown by Pro/INTRALINK scripting methods, you need to use something like the following code:
try {
IL.someMethod(...);
}
catch (Exception e) {
doSomethingHere(...);
}
finally {
alsoDoSomethingHere(...);
}
In other words, you try{} a set of one or more methods, then you catch{} any resulting exceptions. After all of that, the optional finally{} block is executed. In most Java applications, you’ll catch multiple types of exceptions with several catch statements.
Pro/INTRALINK scripting methods seem to throw only one generic type of exception. Here we should appreciate the designers of the Pro/INTRALINK client Java interface. As a Java application, throwing exceptions is exactly what should be happening. Now if we need to process Commonspace objects, which may or may not exist, we can use exception handling to avoid script crashes.
As an example, if you want to take a list of objects from a text file to check out to a workspace, the most reliable way is to Locate the items first and then process the items one by one as they appear in the search results. To do this, we need to know the Name, Branch, Revision, and Version for each object.
To read a list of object names from a text file, first create a FileReader object, then enter a while loop to process each object one at a time.
The following code will try to open file "input.txt". It will then read each line from the file, which is assumed to be tab-delimited data containing Name, Branch, Revision, and Version. It switches the tab character and replaces it with a slash character to form the "object" string.
public void run () throws Exception {
String fileName = "input.txt";
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader( fileName ));
}
catch (Exception e) {
// Print message (shows up in .proi.log file)
System.out.println( "Cannot open file: " + fileName );
return;
}
String line;
// read each line from file
while ((line = br.readLine()) != null) {
// split line into array
String obj[] = line.split("\t");
// skip line if not 4 columns of data
if (obj.length != 4) { continue; }
// change tab to '/' character
String objSpec = line.replaceAll("\t", "/");
// Setup named variables for readability
String objName = obj[0];
String objBranch = obj[1];
String objRev = obj[2];
String objVer = obj[3];
// do most Intralink stuff here ...
}
br.close(); // Very helpful to close the file on Windows!
} // end of run()
Everything that follows will fit into the “do most Intralink stuff here” section. Now that we have the necessary information in objName, objRev, and objVer, we can start the process.
1. Locate an Object
The following code opens a Locate window, adds rules for the search, then performs the search:
// Open Locate Window
IL.setActiveWindow( "Locate", null, "Locate" );
// Clear, then Add search criteria
IL.clearFilter( );
IL.addFilter( "Name", "=", objName );
IL.addFilter( "Branch", "=", objBranch );
IL.addFilter( "Revision", "=", objRev );
IL.addFilter( "Version", "=", objVer );
// Performs the locate
IL.applyFilter( );
2. Select an Object
Once the Locate has finished, we need to determine via select() if anything was found. The arguments to select(), for both Commonspace and Located objects, are the string “PIV” and then a string of the form "abc.prt/main/A/1" ( Name / Branch / Revision / Version ).
If you attempt a select() and no objects or the specific object are not found, an exception will be thrown. If that is not handled, your script is done. To prevent this, the following code will handle the exception.
The continue statement allows you to gracefully bail out and move on to the next item at the top of the while loop. The getMessage() method of the exception object (e) returns the text that would have appeared in the error message box (i.e., “There are no Where Used dependencies for the selected object”). You can use this message if multiple problems can occur for a particular action.
If you're searching for Latest Revision and/or Version, this won't really work because you probably won’t know the Revision and/or Version ahead of time. One way to approach this is to use selectAll() to select all of the objects, and then figure out how many were selected. If you locate by a specific Revision/Version or by Latest, only one object should appear in the search results.
Again, the continue statements let you move on to the next item. If you've moved past the if statement, then you've probably made a successful selection of the object and can proceed to the next step.
3. Create a Workspace
With an object selected, the next task is to perform a check out. Of course, before we can check out objects, we must have a workspace. In this example, we will create a new workspace for each object processed.
String wsName = "test_workspace";
// Create the workspace
try {
IL.createWorkspace( wsName, "" );
}
catch (Exception e) {
// Couldn't create workspace, try deleting first
try {
IL.deleteWorkspace(wsName);
IL.createWorkspace( wsName, "" );
}
catch (Exception e2) {
// Still couldn't create workspace, give up
continue;
}
}
Included is an attempt to delete a workspace of the same name in case the original creation failed. Now you’re ready to perform the check out.
4. Check Out the Object
As with the Locate and Workspace creation, a check out can also throw exceptions. For example, exceptions that may come up are family table version conflicts, insufficient authorizations, etc.
In this case, a quick way to deal with this is to change the Dependency setting to “All” or “Required.” Here is an example that falls back to “Required” if there's a problem. If this still generates an exception, the problem is probably too complex to automate and you should either move on to the next item or stop altogether.
// Caught another exception, some other problem occurred, give up
System.out.println( "Checkout still failed, giving up" );
continue;
}
}
IL.closeWindow(); // Hit ok in dialog box
5. Run a Pro/ENGINEER Trail File
Now that we have a workspace with our object, we can do something with it. A desired task might be to run a trail file in a Pro/ENGINEER session. Perhaps the best way to deal with trail files is either to generate them ahead of time or on the fly within the Java code itself. If we presume a trail file exists, we can run it like this:
System.out.println( "Problem when running trail file: " + x.getMessage() );
}
IL.cancel( ); // Intralink records this for some reason
Thread.currentThread().sleep(30*1000); // sleep for 30 seconds
The sleep statement helps to alleviate a Windows issue, where the script will continue even though Pro/ENGINEER has not fully started. We need this to delete the workspace when the trail file has completed. Without it, the script will delete the workspace before Pro/ENGINEER gets a chance to see it. (On Unix, the script waits for Pro/ENGINEER, and the sleep statement is mostly unnecessary.)
On a side note, I've noticed that when Pro/ENGINEER trail files go out of sequence when started from Pro/INTRALINK 3.3, an exception is not always thrown. Some detection of the end result may therefore be necessary to determine if the trail file session completed successfully.
6. Delete the Workspace
Another unfortunate side-effect of running trail files for extended periods (an hour or more) is that the script may continue even though the trail file is not done. This can cause all sorts of grief if you only want to deal with one Pro/ENGINEER session (and one workspace) at a time.
The workaround for this problem is to try{} to delete the workspace. If an exception is thrown, the workspace cannot be deleted, which usually means that the trail file is probably not done. If you put the deletion attempt in a loop like this, you’ll know when the trail file has finished:
while (true) {
try {
IL.deleteWorkspace( wsName );
}
catch (Exception e) {
// Couldn't delete workspace, wait then try again
Thread.currentThread().sleep(10*1000); // sleep for 10 seconds
continue;
}
break; // workspace was deleted, exit loop
}
Unfortunately, this limits what you can do after the trail file has run, but at least the result is something consistent and reliable.
Toward the end of the while loop, you should close the workspace window. If not, you may end up with some extra windows stemming from each time a workspace is used.
IL.closeWindow(); // Close Workspace window
If we wrap all of these tasks together, the code in the run() method might look something like the following (the name of the class file is irrelevant). Be sure to include the import statement at the top of the file to ensure that the program compiles.
import java.io.*;
public void run () throws Exception {
String fileName = "input.txt";
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader( fileName ));
}
catch (Exception e) {
// Print message (shows up in .proi.log file)
System.out.println( "Cannot open file: " + fileName );
System.out.println( "Problem when running trail file: " + x.getMessage() );
}
IL.cancel( ); // Intralink records this for some reason
Thread.currentThread().sleep(30*1000); // sleep for 30 seconds
while (true) {
try {
IL.deleteWorkspace( wsName );
}
catch (Exception e) {
// Couldn't delete workspace, wait then try again
Thread.sleep(10*1000); // sleep for 10 seconds
continue;
}
break; // workspace was deleted, exit loop
}
IL.closeWindow(); // Workspace window
}
br.close(); // Very helpful to close the file on Windows!
} // end of run()
While more error checking would generally be necessary for production-quality code, this example illustrates the power of exception handling in building robust Pro/INTRALINK scripting applications.
Marc Mettes can be reached by email for questions relating to Pro/INTRALINK Scripting, WebLink, JLink, Pro/TOOLKIT, or Pro/INTRALINK Oracle SQL.