- Show Remaining Articles ( 36 ) Collapse Articles
BBj ODBC Driver
BASIS ODBC Driver (pre-BBj)
- Show Remaining Articles ( 31 ) Collapse Articles
- Show Remaining Articles ( 68 ) Collapse Articles
BBj Enterprise Manager
BASIC Web Utility
- Show Remaining Articles ( 40 ) Collapse Articles
- Show Remaining Articles ( 226 ) Collapse Articles
PRO/5 Data Server
- Show Remaining Articles ( 25 ) Collapse Articles
TAOS: The Developers Workbench
- Show Remaining Articles ( 101 ) Collapse Articles
Sharing BBj Custom Object
BBj has always allowed Custom Objects to be shared between interpreters by placing them in a namespace (BBj’s version of shared memory). BASIS’ recent update to the internal implementation of Custom Objects exposed the fact that, although doing so did not throw an error, it has always had (and still has) the potential to cause race conditions, arbitrary file corruptions, and other unexpected problems in your BBj programs if not used appropriately. Depending on the code in their methods, some Custom Objects are more likely to fail than others. Any ability to execute code on shared Custom Objects was purely accidental. Because of this potential, BASIS recommends that you do NOT share BBj Custom Objects between BBj interpreters. If you choose to do so anyway, there are some steps that your Custom Object code should take in order to minimize the potential for damage.
Sharing BBj Custom Objects between BBj interpreters has the potential to cause subtle errors in your BBj program. When you share a Custom Object, BBj does not immediately error as long as the interpreters sharing the object also share a Session Specific ClassPath (SSCP). Although this constraint is sufficient to avoid issues sharing Java objects, it is not sufficient for BBj Custom Objects. That is because BBj Custom Objects depend upon a much larger set of environment/context values than just the classpath. If any differences exist between the BBj interpreters involved, the potential for sharing errors is considerably greater with BBj Custom Objects. Custom Objects are defined not only by the BBj code in your program and the classpath used to find your class definitions, but also by the classloader that loads them into memory for execution, their interpreter’s BBj PREFIX, various STBL and OPTS settings, and a number of other less common configuration settings. Changing or depending on any of these configuration settings can lead to arbitrary, difficult-to-track problems, especially whenever changes are made to the Custom Object’s class definition. In addition, BBj Custom Objects are scoped per interpreter, this means that a BBj Custom Object from one interpreter is not the same as a BBj Custom Object with the same name in another interpreter and may be using entirely different code. Therefore, casting a BBj Custom Object from one interpreter into a BBj Custom Object with the same name in another interpreter is not safe.
What Happens When Sharing
When BBj Interpreter B tries to call a method on a shared BBj Custom Object that was created by a different BBj Interpreter A, BBj executes the method in Interpreter B. If Interpreter B differs in any way from Interpreter A, those differences can result in unexpected behavior. This occurs because the method code expects an interpreter context matching that of interpreter A.
Here is an example of how sharing Custom Objects could cause a problem. Let us say that we have a BBj Custom Object with a method myMethod(). Interpreter A creates an instance of the class and sticks it into a namespace. Then interpreter B gets the instance out of the namespace and calls myMethod() on it. What happens? That depends on:
- what the implementation of myMethod() actually does
- any differences in the environment between interpreters A and B
Any of the following scenarios is possible:
- (The best case) It could work as expected. For example, adding together a couple of constant static or instance variables (which never change in value) should work, regardless of the environment.
- It could appear to work (not cause any errors), but actually cause apparently random (unexpected) results. For example, if myMethod() tried to add together two global or static variables, there is no telling what the values of those variables are in environment B as opposed to the expected values from environment A.
- It could fail with apparently random errors. For example, it might try to call some BBj program, open a BBj file, or call a static method that is not available or is different because of environment B’s PREFIX.
- It could corrupt environment B. For example, it might change the value of some global or static variable to a value that environment B does not expect.
- It could corrupt files on disk. For example, the BBj Custom Object might have opened a file in the constructor and stored its channel number internally. If it then attempts to write to the file from environment B, where the channel number is not open or (worse yet) is open on a different file, then the method can get an error or write garbage to the file.
Known Sources of Sharing Problems
Here is a list of the known conditions/code actions that could cause incorrect behavior or errors as outlined above. This list is not exhaustive, and there may be additional conditions or code actions that can cause issues:
- Executing a different version of the Custom Object class in Interpreter B than is in use in Interpreter A (this can lead to missing methods, or different method code)
- Accessing global variables, or static variables of the class (since static variables are specific to the BBj session in which the code is running), including:
-Using the value of a global or static variable that can change over time
-Writing a value to a global or static variable
- Relying upon specific OPTS values to define the code’s behavior (reading or writing the value, or both)
- Relying upon specific STBL values to define the code’s behavior (reading or writing the value, or both)
- Using external files, including:
-Opening a file of any type
-Reading from any open file
- Checking for, or relying upon, the existence of an external file via the PREFIX, including:
-CALLs to another BBj source file
-File operations above
- Executing any code that relies upon user permissions to complete. Since Interpreter B can be running as a different user than Interpreter A, these calls can fail, including:
-File operations above
Detecting the Condition
To find out if your program is sharing BBj Custom Objects between BBj interpreters, you can take either of these actions:
- Examine your code for any code that attempts to extract a Custom Object from a namespace using “getValue()” or puts a Custom Object into a namespace using “setValue()”.
- Examine your code for any code that puts an instance of a Custom Object into a static variable of a Java Class that is shared by multiple interpreters.
- Run your application and execute functionality that you believe might be sharing objects. Any methods that try to share objects will fail with an error as well as logging a message to the BBj log that you are attempting to share a non-static BBj Custom Object, with the name of the method called and the name of the object that you are attempting to share.
Correcting Your Code
The simplest way to make your programs more robust and reliable is to not share BBj Custom Objects between interpreters. Use each Custom Object only in the interpreter in which it is created – this will ensure that you do not accidentally cause race conditions, arbitrary file corruptions, or other seemingly random issues in your BBj code. If your code currently puts one or more BBj Custom Objects into a namespace so that it can be shared among multiple BBj interpreters, you have two choices:
- Rewrite your code to no longer share BBj Custom Objects
- Ensure that every BBj Custom Object being shared is defined with the STATIC keyword. For details on doing this, see the explanation of the optional static keyword on the Class Verb page. The STATIC keyword is new in BBj 20.20.
- The optional STATIC keyword indicates that the class (or interface) definition should be shared between interpreters using the same SSCP. All Custom Object dependencies of a STATIC class or interface also need to be STATIC. This would include super classes or interfaces, FIELD types, and METHOD arguments and return types. As a side effect of declaring a class to be STATIC, all of the static fields of the class will also be shared between the interpreters. Since any BBj Custom Object that is defined as STATIC is shared between interpreters, it is also safe (and recommended) to cast BBj Custom Objects to the shared BBj Custom Object Type.
- Be aware that declaring a class to be STATIC (and thus “shareable”) between interpreters does not address all of the potential side effects in the Known Sources of Sharing Problems section. Among others, it does not address the problems that can occur from assuming that the interpreter execution environments are the same, such as:
-External files accessed by both interpreters
-CALL, SCALL, and USE statement dependencies
–OPTS and STBL values