Here are some coding guidelines for new Able beans. Elements of a Java source file are discussed to encourage reuse of design patterns and styles so new Able beans are similar to the current beans. This is how to code, not what to code; for what to code, see Creating an AbleBean. See Sun's Code Conventions for the Java Programming Language for more general and comprehensive Java coding guidelines.
The following the elements of a Java source file are discussed:
There are three main copyright and source protection requirements:
1. Jar/zip protection: a text file in each jar that contains the copyright protection notice. This should be a file named Copyright.txt containing what is called the full protection notice. After the notice all files contained in the jar/zip protected by this notice are supposed to be listed. Our full protection notice is:
Licensed Materials - Property of IBM Package: com.ibm.able (C) Copyright IBM Corp. 1999, 2003. All Rights Reserved. US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.2. Binary/class protection: a long or a short embedded String containing copyright protection. 'Major' classes (the main class in a package, or a class implementing a patent) should have the long form. We defined major as the class com.ibm.able.Able. The long copyright protection notice is the same as the full protection notice above. Licensed Materials - Property of IBM
Package: com.ibm.able
(C) Copyright IBM Corp. 1999, 2003. All Rights Reserved.
US Government Users Restricted Rights - Use, duplication or
disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
Other Able classes use the short protection notice which can be provided as a String or method:
(C) Copyright IBM Corp. 1999, 2003. All Rights Reserved.In Able this is provided by embedding the following method:
/** * Determine the copyright of this class. * * @return A String containing this class's copyright statement. * <p> */ public static String Copyright() { return Able.Copyright; }3. Source code protection, in the form of comments in the header section. This varies depending on the kind of file.
Java files (.java) for internal opensource code:
//********************************************************************* //* Licensed Materials - Property of IBM * //* * //* "Restricted Materials of IBM" * //* * //* Package: com.ibm.able * //* * //* (C) Copyright IBM Corp. 1999, 2003. All Rights Reserved. * //* * //* US Government Users Restricted Rights - Use, duplication or * //* disclosure restricted by GSA ADP Schedule Contract with * //* IBM Corp. * //*********************************************************************For reference only, the object-code-only statement is:
//********************************************************************* //* IBM Confidential * //* * //* OCO Source Materials * //* * //* Package: com.ibm.xxx or product name xxxx-yyy * //* * //* (C) Copyright IBM Corp. year1, year2 * //* * //* The source code for this program is not published or * //* otherwise divested of its trade secrets, irrespective of * //* what has been deposited with the US Copyright Office. * //*********************************************************************Example source code is:
//==================================================================== // // Licensed Materials - Property of IBM // // "Restricted Materials of IBM" // // Product: com.ibm.able.examples // // (C) Copyright IBM Corp. 2001, 2003 All Rights Reserved. // // US Government Users Restricted Rights - Use, duplication or // disclosure restricted by GSA ADP Schedule Contract with // IBM Corp. // // // DISCLAIMER // ---------- // // This material contains programming source code for your consideration. // These examples have not been thoroughly tested under all conditions. // IBM, therefore, cannot guarantee or imply reliability, serviceability, // performance or function of these programs. All programs contained // herein are provided to you "AS IS". THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY // DISCLAIMED. // //====================================================================
Properties (.properties) files:
- =========================================================================== - Licensed Materials - Property of IBM - "Restricted Materials of IBM" - Package: com.ibm.able - - (C) Copyright IBM Corp. 1999, 2003. All Rights Reserved. - ===========================================================================
HTML (.html or .htm) files:
<!- =========================================================================== Licensed Materials - Property of IBM "Restricted Materials of IBM" Package: com.ibm.able (C) Copyright IBM Corp. 1999, 2003. All Rights Reserved. =========================================================================== ->
The objectives are:
- Provide an NLS-enabled message to the user or rules developer via the message logger
- Provide a stack trace to the developer or able programmer) via the trace logger
- Throw an exception embedding the original exception as the cause.
When wrappering a base Java exception, in many cases we can rely on the exception caught to provide an appropriate NLS-enabled message like this:
catch(IOException theException) { throw new AbleException(theException.getLocalizedMessage(),theException); }Better is to provide additional context to a base Java exception by supplying your own text message. The message should be retrieved from a message bundle and used as shown:
catch(java.net.MalformedURLException theException) { String msg = Able.NlsMsg("Ex_NamingRebind", new Object[] {this.agentName,this.agentHost}); throw new AbleException(msg, theException); }If you handle an exception, you may wish to provide a warning or informational message to the user, and/or provide a stack trace to the developer.
catch(java.net.MalformedURLException theException) { String msg = Able.NlsMsg("Ex_NamingRebind", new Object[] {this.agentName,this.agentHost}); logger.text(Able.MSG_INFO,this,"rmiRebind",msg); if (trace.isLogging()) trace.exception(Able.TRC_LOW,this,"rmiRebind",theException); lclName = "A default name and host"; }When creating a new exception which is not based on a Java exception, again the message must be retrieved from a message bundle. Note the stacktrace will be based on the line where the AbleException is constructed.
String msg = Able.NlsMsg("Ex_NamingRebind", new Object[] {this.agentName,this.agentHost}); AbleException exp = new AbleException(msg); logger.text(Able.MSG_ERROR,this,"rmiRebind",msg); if (trace.isLogging()) trace.exception(Able.TRC_LOW,this,"rmiRebind",exp); throw exp;
A good general source is Sun's How to Write Doc Comments for the Javadoc Tool.
Able conventions are:
- Javadoc is generated and distributed for protected and public methods and fields.
- Methods: private methods should be documented if their function is nontrivial.
- Use the @version tag's CVS version; ie, let CVS maintain the version number.
* @version $Revision: 1.84 $, $Date: 2002/11/22 21:29:41 $- Do not use the @author tag.
Some of the more relevant general guidelines are:
- Methods implementing interfaces need only provide javadoc if the interface javadoc is insufficient. Otherwise use a line like this:
// javadoc provided by interface com.ibm.able.xyz- Methods overriding superclass methods should describe the alternate behavior provided and indicate if the overridden method is called, and if so if before or after the additional function is excecuted.
Able wrappers the Logging for Java utility called JLog. AbleLogger is the interface we chose to use as a JLog wrapper, and AbleTraceLogger is the class that implements that interface. JLog's design suggests, and Able provides and uses, two logging fields in AbleObject:
- Message logging, whose output is intended for end users and should be NLS translatable. Levels are Error, Warning, and Informational, and by default message logging is set to the Error level.
logger.message(Able.MSG_ERROR,this,"methodName","messageBundleKey",new Object[]{"why"});
- Trace logging, whose output is intended for developers and need not be NLS translatable. Levels are High, Medium, and Low and by default trace logging is not enabled. To avoid the overhead of creating trace messages when tracing is disabled, test to see if the tracer is logging.
if (trace.isLogging()) trace.text(Able.TRC_LOW,this,"methodName","A low level trace message");
Debug-only tracing can be eliminated from production output using the static Able.Debug boolean:
if (Able.Debug && trace.isLogging()) trace.text(Able.TRC_LOW,this,"methodName","A low level trace message");
Helper methods for starting and stopping loggers, changing levels, adding and removing console and file handlers, and formatting logger output are all provided as static methods in the Able class. The Able class instantiates a static global logger (Able.MessageLog) and a static global trace (Able.TraceLog) objects which are referenced by all classes which extend AbleObject. The local references in AbleObject are logger and trace respectively. In order to debug beans during development, Able provides the ability to switch to bean level tracing to enable individual beans to have their own trace logger object.
Here are some guidelines on what to trace and log:
- Every error or non-standard condition or exit, external commands, control passing from Java to native.
- All information which won't degrade performance, especially major steps in the process such as entry points in init, reset.
- If you create an exception, use the exception method to trace it - level should be low.
- If you catch an exception and handle it, log it as either warning or informational. If you can't handle it, you probably ought not catch it. If you do catch an exception and rethrow it as another kind of exception, nest the original exception by including it in the constructor. You may want to log the message as an error and/or trace the exception so the stacktrace is visible.
- Consider tracing at major methods such as init and reset; use either ext, entry, or exit calls at level high.
- Consider tracing or logging when configuration parameters are set, using either medium or warning level.
- Use the getLocalizedMessage() method to retrieve text from an exception.
- Any text for the Message logger or ruleset inference trace must be obtained from the message bundle.
- Libraries like AbleBeanLib must validate their parameters and log and throw exceptions when invalid.
If you see this message:
LOG0004E No handlers are registered with the logger AbleMessageLog.
You have no message logger started. You either have your preferences set to provide no message logging, or you have not started the Able logging facilities. When the Able.class is loaded, a static initializer starts whatever trace and log facilities are defined in preferences. You can also start these facilities from your api if you wish via::
Able.startMessageAndTraceLogging();If you see this message:
LOG0004E No handlers are registered with the logger AbleTraceLog.
You have no trace logger started. You either have your preferences set to provide no trace logging, you have not started the Able logging facilities (see description of AbleMessageLog), or you have not prefaced your trace statement with the conditional statement:
if (trace.isLogging()) trace.text(...)Trace and log levels
We have standardized three levels of logging output for logging and tracing as follows:
Message logging Trace logging Low: only the most essential such as errors; no impact to performance Able.MSG_ERROR
Exception message text
Able.TRC_LOW
Exception stack traceMedium: significant actions and progress; minimal impact to performance Able.MSG_WARNING
Autonomic action takenAble.TRC_MEDIUM
Configuration parameter changedHigh: detailed activities; expect performance degradation
Able.MSG_INFO
Transaction begun or completed, property modifiedAble.TRC_HIGH
Method entry or exit, property modifiedTracing in rulesets
AbleRuleset objects always provide their own unique trace logger. Any handlers registered to the static trace logger are shared by the ruleset trace logger.
Applications such as editors may be interested in specific kinds of rule functions, and may provide handlers to the ruleset to be added to the ruleset's trace logger. In addition, ruleset statements themselves may manipulate these application-specific tracing features.
- Parse handler, for trace statements which need not be translated and are of interest primarily to the developers of the Able parsing routines. Parse output is considered high level. Parse exception messages are passed to the caller, and not logged by the parser itself.
- Inference handler, for display of intermediate inferencing steps as well as final results. Inference statements are to be translated and can be high, medium, or low level. Ruleset developers are primary users of inference output.
- Base handler, for trace statements which show activity and progression through the ruleset API. Level may be high, medium, or low. Those developers using the various ruleset APIs to construct rulesets programmatically will be interested in base trace output. Base trace is not translated.
Task Application providing handlers or using default console handler Ruleset Start inference tracing* myRuleset.setInferenceTraceHandler(myHandler,Able.TRC_LOW);
myRuleset.setInferenceTraceLevel(ARL.LOW);this.setInferenceTraceLevel(ARL.LOW); Change trace level myRuleset.setInferenceTraceHandler(myHandler,Able.TRC_HIGH);
myRuleset.setInferenceTraceLevel(ARL.HIGH);this.setInferenceTraceLevel(ARL.HIGH); Stop inference tracing myRuleset.setInferenceTraceHandler(myHandlerAble.TRC_NONE);
myRuleset.setInferenceTraceLevel(ARL.NONE);this.setInferenceTraceLevel(ARL.NONE); Check inference level myRuleset.isInferenceTraceLow(); this.isInferenceTraceLow(); Send inference message if (myRuleset.isInferenceTraceLow()) {
myTrace.message(this, "methodname", Able.TRC_LOW, "Resource_key",new Object[]{parm1, parm2});
}trace("We are nearly here");
traceFormat("We are nearly {0}","here");