Java Programming Standards and Guidelines
Ramanand Singh
Java programming standards and
guidelines for writing better Java code has been discussed. The standards
and guidelines presented in this white paper are based on established standards
in the Java development community, individual real-world experience from numerous
object-oriented development projects, local requirements and needs, as well
as on proven software engineering principles that lead to improved development
productivity, greater maintainability, and enhanced scalability. The use of these standards should result in better
readable code and should encourage adherence.
The purpose of this document is not to restrict programming innovations, but rather to impose a consistent standards and guidelines for all programs. This will help in debugging and maintenance of the programs by the current and the future software engineers of the development teams. Programming standards and guidelines is an important part of good software engineering practices. The goal is to write code that is clear and easy to understand, reducing the effort required to make future extensions or modifications.
Anyone
with a little knowledge of a programming language can write code that a computer
can easily understand. However, good programmers write code that humans can
understand. Before producing great code, one needs to develop a process for
writing great code.
Good code
does not necessarily mean just well documented code. For example, rather than
trying to document how you perform a complex algorithm, try to make the algorithm
easier to read by introducing more identifiers. This helps in the future in
case of algorithm enhancement and maintenance. To demonstrate this idea, let
us look at an example of determining if the given year is a leap year.
Algorithm
Statement: This
algorithm statement can become a part of the method description in all implementations
presented here, and hence commented.
/**
* Determine if the given year is a leap year. <p>
* The Gregorian calendar principle states that a leap year occurs
every
* fourth year, except every 100 years, and except every 400 years.
<p>
* If the year is evenly divisible by 400 or is evenly divisible by
* 4 and not by 100, then it is a leap year. <p>
* @param year The year to be tested. Make sure it is a 4 digit year.<p>
* @return true if "year" is a leap year. <p>
*/
Original
Implementation:
public boolean isLeapYear(int year)
{
return (((y % 400) == 0)
|| (((y % 4) == 0) && ((y % 100) != 0)));
}
Modified
implementation for better readability:
public boolean isLeapYear(int year)
{
boolean y4 = ((year % 4)
== 0) ;
boolean y100 = ((year %
100) == 0) ;
boolean y400 = ((year %
400) == 0) ;
return (y400 || (y4 &&
! y100));
}
Alternate
modified implementation for better readability:
public boolean isLeapYear(int year)
{
boolean returnVal = false
;
if ((year % 400) == 0)
{
// this is definitely
a leap year
returnVal = true ;
}
else if ((year % 4) ==
0)
{
// this is probably a leap year
if ((year % 100) != 0)
{
// this is definitely
a leap year
returnVal
= true;
}
}
return returnVal ;
}
These small code snippets show the need for
a programming and coding standard for any development team.
This document
contains both standards (also referred to as conventions) and guidelines regarding
writing Java based programs. The convention sections of the document describe
coding standards that are "necessary and required" coding
practices and that has been agreed upon by members of the Java Product Development
teams. Everyone in these teams is expected to follow these standards.
The guideline
sections discusses the coding standards that are "suggested"
coding practices and have been written to recognize the need for individuality
and for common coding practices. The purpose of the guidelines is to provide
a framework upon which we can all create better code. However, the guidelines are not meant to impede engineering efforts
when these guidelines are found to be in direct conflict with an individual's
preference, so long as that preference is implemented consistently and is
well documented. Finally, because we recognize that this opens the code upon
to individual stylist coding habits, it is important that these habits are
well documented and will then become the basis for all other updates within
the affected files, i.e. when in someone else's code do as they do.
This document
targets the professional software engineers and developers who are interested
in writing Java code that is easy to maintain and to enhance; increasing their
productivities; and working as productive members of a Java development team.
The document also provides a basis for software development managers, product
managers, and other management staff members to make sure that software code
produced by their development teams are consistent across the projects.
An introduction
on the Java programming standards and guidelines has been presented in Section
1, including the document scopes and target audience. Section 2 presents the naming conventions established for Java
coding. Accessibility standards has been discussed in Section 3. Section 4 of the document discusses general guidelines
for Java programming. Guidelines on writing code comments are presented in
Section 5. A general list of suggestions is presented in Section 6. Section
7 discusses the Java source file organization. An example Java program file
is presented in Section 8.
Naming
conventions make programs easier to read by giving information about the function
of the identifier - for example, whether it's a package, class, interface, or constant. This can be helpful in understanding
the code.
In Java
programming language, the file name containing a public interface, class,
or exception must be named exactly the same as the name of the interface,
class, or exception, respectively. The extension of the program file (containing
the code) must be .java.
Examples:
Ilogger.java, Logger.java, LogException.java
Each Java
source file contains a single public class, exception, or interface. When
private classes and interfaces are associated with a public class, they can
be put in the same source file (although
not recommended) as the public class or interface. The public class or interface
should be the first class or interface in the file.
The leading
components (prefixes) of a unique package name are always written in all-lowercase
ASCII letters. A package can be made unique by prefixing the company domain
name to it. This will make the first component to be one of the top-level
domain (TLD) names, currently com, edu, gov, mil, net, org, info, ws, tv, or one of the English two-letter
codes identifying countries as specified in ISO Standard 3166, 1981. However,
the company domain name in the package name is not necessary.
Subsequent
components of the package name are usually directory hierarchy names for the
source code. However, it need not be the entire directory path. The initial
portion of the directory path of the source code, omitted from the package
name, must be included into the classpath environment variable for the code
to compile.
Example: Let us assume that source code for
XML related utilities and Java Collection reside In directories /export/home/johndoe/project/ws/Nalanda/util/xml
and /export/home/johndoe/tools/java/util respectively. The corresponding package
names would be:
package ws.nalanda.util.xml;
package java.util;
if we agree to add /export/home/johndoe/project and /export/home/johndoe/tools to the value of CLASSPATH environment variable.
Class name
must be a proper noun or a combination of proper nouns. The name should be
simple, natural, and descriptive. It should always use whole word and should
avoid obscure acronyms and abbreviations. For a multiple words class name,
each of the words must be written in mixed case with only first letter of
the word capitalized. If an abbreviation is used, it must also follow the
mixed case convention. For example, if the abbreviation HTTP is to be used
in a class name, it must be written as Http.
Example: Customer, HttpRequest, XmlDocumentManager
The name
of an exception should follow the same naming conventions as that of a class.
However, the word “Exception” must be suffixed in the name.
Example: ConfigurationException, InsufficientResourcesException
The interface
naming convention is exactly the same as that of the class. However, the character
“I” should be prefixed in the name.
Example: IComponent, IProduct, IService, INode,
IResultSetProcessor
Variable
names should be short and meaningful. The choice of variable names should
clearly indicate to the casual observer the intent of its use.
The variable
names for these variable types must be in all lower cases. In case of a multiple
words name, the subsequent words will have their first letters capitalized.
Examples:
public static Logger globalLogger;
private static int currentLogLevel;
private
String inputFilename;
protected JndiServices
lookupService;
private Logger[] loggerList;
Local variable
names should be short and meaningful. The names must be in all lower case.
For a multiple words name, all the words will be combined (or, separated –
depending upon your view) with an underscore (_) character. The single character
variable names (e.g., i, k, p, etc.) must not be used except for
temporary throwaway (loop counters) variables.
Example: account_balance, address.
The names
of the constants must be all uppercase. Multiple words in the constant names
must be separated by the character underscore (_).
Examples:
public static final String
CONFIG_FILE = “myConfig.xml”;
public static final int
MAX_SIZE = 37;
The constructor
names of a class and exception must be the same as the class and exception
names themselves, respectively. The constructor may accept parameters as its
arguments, however.
Method
names must be verbs and written in mixed case starting with lower case. The
subsequent words in the multiple words names will have their first letters
in upper case.
Methods
with boolean return types must start with an interrogative verb. Negated boolean
variable names (e.g., isNotError(), isNotFound(),
etc.) must be avoided. The accessor method
names for a particular member data will have either get or set prefixed to the data member name,
or the method name can be the same as data member name.
Examples:
public void processResult(…);
public Object next();
public boolean hasNext();
public void setAddress(Address address);
or,
public void address(Address address);
public Address getAddress(); or,
public Address address();
Parameters
are arguments to member functions and constructors. The parameter names must
follow the convention of member data. However, in some cases, naming parameters
as their data types can be more useful.
Examples:
public Document createDocument(String xmlFilename);
public void processKeyValues(Element element, String key,
Vector values);
public Object lookup(String jndiName);
A component
factory is a public class that is based on factory design pattern and implements
only static methods. These static methods are either “Factory functions” or
“component constructors”. Factory class names must follow the same convention
as that of any other classes. However, the word “Factory” must be suffixed
in the class name.
Example: DocumentBuilderFactory.
Visibility
of an entity determines who can have access to the entity and who are prohibited
from it. Various entities of Java programming language have different visibilities
and for good reasons.
Classes
may have either public or and default visibility. Follow the conventions below
to determine the class visibility:
Class visibility
and accessibility can further be controlled using final and abstract keywords.
An abstract class can not be instantiated, but can be extended. On the other
hand, a final class can be extended but not be instantiated.
Both class
variables (static fields) and instance variables can be of types static (only
for class variables), final, transient, and volatile. The final data members
are those whose value cannot be changes after its initialization. Class constants
are examples of such fields. The transient member data are used to emulate
the default serialization of the original class and to preserve the serialized
format. A volatile data type is an alternate mechanism for synchronization.
A volatile type indicates that its value can change at any times, without
any knowledge of the compiler, and thus prevents the compiler from making
any assumptions about the field (member data) value.
A member
data can have its access modifier or visibility control as private, package,
protected, or public. The visibility control guidelines for member data vary
for class variables from the instance variables.
Public
visibility of a class variables must be avoided unless there is a compelling
reasons for doing so.
Instance
variables must always be defined private. There is absolutely no reason for
instance variables to be defined otherwise. Outside access to the instance
variables can be provided through accessor methods.
Constructor
visibility follows the same conventions as that of member functions. A protected
or private constructors are usually used for making the class a singleton.
A member
function can be private, protected, or public – indicated by these keywords.
The following conventions must be followed in deciding the visibility of a
member function:
There is
also another type of visibility called default visibility. The default
visibility is indicated by leaving the visibility type without any keyword.
With a default visibility, the member function is effectively public to all
other classes within the same package, but private to classes external to
the package. This is sometimes called package visibility or friendly visibility.
This is an interesting feature, but be careful with its use. I use it when
I'm building domain components, collections of classes that implement a cohesive
business concept such as "Customer", to restrict access to only
the classes within the component/package. One should, in general, avoid the
use of default visibility.
This section
presents a set of guidelines on how to place a particular Java code entity
in a program source. Every member of the development team is encouraged to
follow the guidelines presented in this section.
Indentation
makes code more readable showing the various steps clearly. Indentation should
be done with white spaces rather than tabs. Definition and settings for tabs
varies across organizations, editing tools, and other factors. In general,
an indentation of three (3) white spaces should be placed between two levels
of codes. For example, in a if clause of the program, the line with conditional
expressions and the following statements are at two different levels.
Example:
if
(condition) { // level 1
Statement; // level 2
}
Examples:
DocumentBuilderFactory docBuilderFactory =
DocumentBuilderFactory.newInstance();
Home = (RegistrationHome)EJBUtil.getHome(JNDINames.REGISTRATION_EJBHOME,
RegistrationHome.class,
url);
outputDirectory = ConfigMgr.getParameterValue(init
+ "OutputDirectory");
LogMgr.log(LogMgr.DEBUGLOG,
LogMgr.DEBUG_METHOD, this,
"hasWork(): " + work);
alpha = (aLongBooleanExpression)
? beta : gamma;
alpha = (aLongBooleanExpression)
? beta
: gamma;
alpha = (aLongBooleanExpression)
? beta
: gamma;
Examples:
int current_level; // Its value depends upon later computation
boolean result = false;
// default return value for an
// interrogative method.
private Address address; // instance variable
or member data
Try avoiding
the following types of code:
int current_level, current_size;
int
category, values[]; // wrong
◦ Declarations
should be placed at the beginning of blocks, except for loop indices.
Examples:
void doSomething() {
int
int1 = 0; // beginning of method
block
if
(condition) {
int int2 = 0;
// beginning of "if" block
...
}
}
◦ Avoid
local declarations that hide declarations at higher levels. In other words,
do not declare the same variable name in an inner block which has already
been declared in its outer block. However, such declarations are legal.
Example::
int count;
...
doSomething() {
if (condition) {
int count = 0;
// AVOID!
...
}
...
}
◦ Simple: Avoid multiple statements on a line.
◦ if-else:
Always use braces for the statement, even if it is a single statement.
Example:
if (condition == true) {
Perform_statement;
}
◦ for: Avoid too many (more than two) initialization
variables in the for loop. A for loop
may be empty (i.e., it may not have any statements). In such cases, terminate
the for loop by placing a semi-colon (;) after the closing parenthesis of
the loop.
◦ while: A while loop may be empty (i.e., it may not
have any statements). In such cases, terminate the while loop by placing a semi-colon (;) after the closing parenthesis of
the loop.
◦ Try-catch-finally: A try-catch statement may be followed by a finally block, although it is not mandatory.
◦ witch: If a case does not include a break statement, add a comment in its place to indicate that the case is falling through. Always use the default case inside a switch statement and always use break statement in the default case (even though it is redundant).
◦ return: Avoid using parentheses in return
statement, unless they make the return value more understandable.
Example:
return result;
return
(result ? true : false);
White spaces
improve readability by separating sections of code that are logically related.
White spaces can be added in the code either as blank lines or as blank spaces.
Other white spaces (such as page break, special characters, etc.) should be
avoided in the code. In general, all identifiers should be surrounded by white
spaces.
Some utilities
will cleanly select an identifier when you double click on it. Some of these
double-click-functions are strictly space delimited, so any surrounding characters
might accidentally get included in an otherwise clean selection. Therefore,
white spaces (blank spaces and blank lines) are required around all identifiers.
Here is
a set of suggested guidelines for using white spaces in Java code:
Examples:
These code snippets show the guidelines stated above.
for (int I = 0, k = 0; I < icount, k <= kcount; I++, k++) {
x += y;
x = (a + c) * (a – d);
y = (double)c;
System.err.println(“Final
value of x is: “ + x );
}
if (a == lowValue) {
compueSomething();
} else if (a == mediumValue)
{
computeSomethingElse();
} else if (a == highValue)
{
computeSomethingElseYet();
}
value = (potential * oilDensity) / constant1
+
(depth * waterDensity) /
constant2
+ (zCoordinateValue *
gasDensity) / constant3;
minPosition = computeDistance(min,
x, y, z);
averagePosition = computeDistance(average, x, y, z);
switch(value) {
case PHASE_OIL : phaseString = "Oil"; break;
case PHASE_WATER: phaseString
= "Water"; break;
case PHASE_GAS : phaseString = "Gas"; break;
}
General examples of good and not so good practices:
|
Code
section |
Use |
Avoid |
|
Method Names |
foo(i); startProcessing(); |
foo (i); startProcessing
(); |
|
Array
declarations |
args[0]; tens[I]; |
args [0]; tens [i]; |
|
Increment
& decrement operators |
++counter; i--; |
++ counter; i --; |
|
Cast
Operator |
(Vector)v.get(3); |
(Vector) v.get(
3 ); ( Vector )v.get(
3 ); |
◦
Avoid
using embedded assignments. Java compiler takes care of optimizations.
Example:
|
Use |
Avoid |
|
k = p + q; x = k + r; |
x = (k = p +
q) + r; |
◦
Avoid
assigning several variables to the same value in a single statement. Even
though it is quite legal, it makes code harder to read and understand.
Example:
|
Use |
Avoid |
|
variable1 = value; variable2 = value; variable3 = value; |
variable1 = variable2 = variable3 = value; |
◦
Avoid
using assignment operators which can make your code confusing.
Example:
|
Use |
Avoid |
|
while ((i++ = j++) != 0) { |
while (i++ =
j++) { |
There are
two ways of placing the opening braces in Java coding, as listed below. Pick
one style and stick with it. If you find your team member code with alternate
style, please respect the individuality of your team mate.
Examples:
|
Condition |
Braces Placement Style
|
Alternate
Braces Placement Style |
|
if-then block |
if (conditional-expression) { statement; } else { alternate_statement; } |
if (conditional-expression)
{ statement; } else { alternate_statement; } |
|
While |
while (expression) { statement; } |
while (expression)
{ Statement; } |
|
do..while |
do { Statement; } while(expression); |
do { Statement; } while(expression); |
|
switch |
switch (expression)
{ case n: statement; break; case x: statement; //continue to default default: //always add the //default case statement; break; } |
switch (expression)
{ case n: statement; break; case x: statement; //continue to //default case default: //always add the //default case statement; break; } |
|
try-catch-finally |
try { statement; } catch(ExceptionClass
e) { statement; } finally { statement; } |
try { statement; } catch(ExceptionClass
e) { statement; } finally { statement; } |
.
A return
value statement should be very precise, clear, and unambiguous to show the
clear intent of the program segment. Try not to clutter your code with redundant
statements in trying to make code clearer to understand.
Example:
|
Use |
Avoid |
|
return boolean_return_value; |
if (boolean_return_value)
{ return true; } else { return false; } |
|
return (high_temperature
? “hot” : “cold”); |
if (high_temperature)
{ return “hot”; } return “cold”; |
◦
Avoid
using an object reference to access a class (static) variable or method. Use
a class name instead.
Example:
|
Use |
Avoid |
|
MyClass.doSomething(); |
myClassRef.doSomething(); |
|
MyClass.GLOBAL_INIT |
myClassRef.GLOBAL_INIT; |
Additional
guidelines for enhancing your java code are described in this subsection.
When you design your class, you should design its unit test. When you design your package, you should design your integration test. You are NOT done with the implementation of a class until its unit test is implemented and can be run successfully. You are NOT done with your package implementation until all unit tests are coded and run successfully, and the integration tests (if appropriate) are coded and run successfully.
Implementation
comments and documentation comments are two kinds of comments a Java program
can have. Implementation comments are meant for commenting out code or for
comments about the particular implementation. Documentation (also referred
to as Doc) comments are meant to describe the specification of the code, from
an implementation-free perspective to be read by developers who might not
necessarily have the source code at hand.
Comments
should be used to give overviews of code and provide additional information
that
comment.
Discussion
of nontrivial or obscure design decisions is appropriate, but avoid duplicating
information that is present in (and clear from) the code. It is too easy for
redundant comments to get out of date. In general, avoid any comments that
are likely to get out of date as the code evolves.
The high
frequency of comments sometimes reflects poor quality of code. When you feel
compelled to add a comment, consider rewriting the code to make it clearer.
Comments should never include special characters such as form-feed, backspace,
graphics characters, etc.
Guidelines for various levels of implementation comments are presented here. It is assumed that these guidelines will help developers write comments to make their Java code understandable to human readers.
Block comments
are used to provide descriptions of files, methods, and algorithms. Such comments
may be used at the beginning of each file and before each method. They can
also be used within methods. Block comments inside a function or method should
be indented to the same level as the code they describe. A block comment should
be preceded by a blank line to set it apart from the rest of the code. Block
comments can start with /*-, which is recognized by the indent program as
the beginning of a block comment that should not be reformatted.
Examples:
/**
* This is a sample block comment.
*/
/*-
* This is a sample block comment with some
very special formatting
* that I want indent program to ignore.
*
* one
* two
* three
*/
Short comments
can appear on a single line indented to the level of the code that follows.
If a
comment
can't be written in a single line, it should follow the block comment format
described above. A single-line comment should be preceded by a blank line.
Examples:
1. Comment
for instance variable
/** An instance variable to save the state of the object **/
private Object state;
2. Comments
within a method
if (condition) {
/* Handle the condition. */
...
}
Trailing
comments are very short that can appear on the same line as the code they
describe. Such comments should be shifted far enough right to separate them
from the statements. If more than one short comment appears in a chunk of
code, they should all be indented to the same tab setting.
Example:
if (value == MAX_VALUE) {
return true; /* special case */
} else {
return isPrime(value); /* works only for odd value */
}
The // comment delimiter can comment out
a complete line or only a partial line. It shouldn't be used on consecutive
multiple lines for text comments; however, it can be used in consecutive multiple
lines for commenting out sections of code.
Examples:
if (foo > 1) {
// Do a double-flip.
...
} else {
return false; // Explain why here.
}
//if (bar > 1) {
//
// //
Do a triple-flip.
// ...
//}
//else {
// return
false;
//}
JavaDoc
comments will be used to document all classes and members (data and functions).
These comments must immediately precede the item they are documenting. The
documentation comments, usually known as doc comments, let one associate reference
documentations for programmers directly with the code. The contents of the
doc comments are used to generate reference documentation, typically presented
using HTML. A common way to generate reference documentation is to run the
javadoc command on the package or types; hence, the generated document
is called javadoc.
JavaDoc
permits any HTML tag desired, but requests that one must not use the header
tags (<h1>, <h2>, etc.). One might want to use <b> .. </b>
to bold or <i> .. </i> to italicize.
Detail
information on writing javadoc comments can be found in the document “How
to Write Doc Comments for Javadoc”(see resources). General guidelines for
writing document comments are briefed in this subsection, by listing appropriate
javadoc tags for various document comment sections..
Various
important fields for classes and interfaces are author name, version number,
reference links, availability since, and deprecation status.
Only tags
for the member data include @see, @since, and @deprecated. These tags are described above.
In addition
to @see, @since, and @deprecated
(described above) tags, the constructors and member functions can have
the following tags:
There are
a number of practices one should get in habit of during programming. These
practices make the code more readable and efficient.
|
Use |
Avoid |
|
boolean done = false ; while (!done) { ... } |
boolean done = false ; do { ... } while(!done) |
Examples:
|
Use |
Avoid |
|
foo( x ) ; x++ ; |
foo( x++ ); |
|
y += 100 * x ; x++ ; |
y += 100 * x++ ; |
Each Java
source file contains a single public programming unit (class, exception, or interface). When private programming units
are associated with a public programming units, they should be put in the
same source file as the public programming unit. The public programming unit
should be the first unit in the file.
The layout
for a class will be broken up into the following main sections: Beginning
Comments, File Description; Package
Name, Imports, Class/Interface, Constants, Methods, protected and private
members. Each section will be prefaced by an appropriate header block
comment defining the section. The white spacing guidelines should be maintained
as described in this document.
All source
files should begin with a comment block that lists the filename, class name,
version information, date, and copyright notice.
Example:
/**
* $Id $
*
* Class Name(s): MyExample
* Date: 2001-oct-01
*
* Copyright
© 2001, Nalanda Technology, Inc.
* 12907 Locksley Ct., Herndon, VA 20171.
* All Rights Reserved.
*/
Package
name should occur on the first non-commented line of the source file and should
be following the naming conventions defined in this document. A blank line
should be added before the package declaration.
Example:
com.ti.education.framework;
Immediately
following the package name should be the import statements for imported class
names. A blank line should be added
before starting import statements. The import statements should be sorted
with the most fundamental packages first, grouped by packages, and within
a package the class names should be in ascending sorted order. A blank line
should be added between two groups.
This segment
of a source file presents the general description of the class or interface.
Optionally, it may list the author name and the version number of the class
or interface.
Example:
/**
* Class/Interface description should go here.
*
* @version 1.47 2001-oct-01
* @author Ramanand Singh
*/
Class or
Interface declaration should follow immediately after its documentation comments,
as described above.
Examples:
public class DocumentManager
public abstract class AbstractBaseProduct;
public final
class NoneExtendingConcreteProduct extends AbstractBaseProduct
public strictfp class MathLab
This comment
should contain any class-wide or interface-wide information that wasn't appropriate
for the class/interface documentation comment.
Member
data should be declared in the ascending order of class constants, class variables,
and instance variables. Variables in one category should be separated by a
blank line from variables in the next category. In each of these categories,
the variables must be placed in the order of their accessibilities – first
public variables, followed by protected variables, then package level (no
access modified), and finally private variables.
Each of
these variables should be preceded by an appropriate single-line or multiple-line
comments. Alternatively, if the comment is small, it can be placed as trailing
comments following the variable declarations (but on the same source line.)
All the
class constructors should be grouped together and placed immediately after
member data of the class. There must be a separation of at least one blank
line between the member data declaration and the constructors.
A separate
documentation section must precede the constructors as per documentation guidelines
described in this document..
Class member
functions (or, methods) should be grouped by functionality rather than by
scope or accessibility. For example, a private class method can be in between
two public instance methods. The goal is to make reading and understanding
the code easier.
A separate
documentation section must precede the member functions as per documentation
guidelines described in this document..
A closing
brace “}” must
be the last uncommented statement for the class. This brace must be on a separate
line all by itself.
This example class has been provided for serving
as an elaborate example in organizing java source file. This is not a complete
and working Java class. It needs a number of other classes
and interfaces to
get this class even to compile successfully. However, this class example can
serve as a reference guide both during studying this document and during practicing
standards and guidelines outlined in this document.
/*
Class: DocumentManager
* $Id$
* © 2001, Nalanda Technology, Inc., its vendors,
and suppliers.
* 12907 Locksley Ct., Herndon, VA 20171
* ALL RIGHTS RESERVED.
*
* Date 2001-sep-19
*/
package
ws.Nalanda.util.xml;
import
org.w3c.dom.CDATASection;
import
org.w3c.dom.Document;
import
org.w3c.dom.Element;
import
org.w3c.dom.NamedNodeMap;
import
org.w3c.dom.Node;
import
org.w3c.dom.NodeList;
import
org.w3c.dom.Text;
import
org.xml.sax.SAXException;
import
javax.xml.parsers.DocumentBuilder;
import
javax.xml.parsers.DocumentBuilderFactory;
import
javax.xml.parsers.ParserConfigurationException;
import
java.io.File;
import
java.io.IOException;
import
java.io.PrintWriter;
import
java.util.Iterator;
import
java.util.Vector;
/**
* DocumentManager class provides auxiliary services
in dealing with
* XML documents, such as copying, cloning, appending,
creating,
*
parsing, etc. This is a singleton class providing access to its
*
methods without carrying around its once created instances. This
*
is a singleton class providing its services without instantiating it
*
in every use places.
*
@see javax.xml.parsers.DocumentBuilderFactory
*/
public
final class DocumentManager extends AbstractDocumentManager
implements IDocumentManager
{
/** constants */
private static final String SINGLE_CARDINALITY
= "1";
/** class variables */
private static DocumentManager instance_
= null;
/**
* a protected constructor for preventing
users from accidental
* direct instantiation. The main purpose
for this constructor is
* to make the class instantiation transparent.
protected DocumentManager()
{
setInstance(this);
}
/**
* Sets the instance of the class to the
supplied instance.
* @param instance. The instance of the class.
*/
public void setInstance(DocumentManager instance)
{
this.instance_
= instance;
}
/**
* retrieves the instance of this class for
easy access.
* @return DocumentManager. The instance
of the class.
*/
public static DocumentManager getInstance()
{
if
(instance_ == null) {
instance_
= new DocumentManager();
}
return
instance_;
}
/**
* creates an empty XML document (DOM).
* @return Document the resulting DOM-tree
* @throws DocumentException. An exception
in case of failure of
*
any of the steps involved in
* creating DOM-tree.
*/
public Document createDocument() throws DocumentException
{
Document
doc = null;
try
{
// Create an instance of the DocumentBuilderFactory
DocumentBuilderFactory docBuilderFactory =
DocumentBuilderFactory.newInstance();
//Get DocumentBuilder from the factory we just got above.
DocumentBuilder docBuilder =
docBuilderFactory.newDocumentBuilder();
// turn it into an in-memory object
doc = docBuilder.newDocument();
}
catch
(ParserConfigurationException pce)
{
throw new DocumentException(
"ParserConfigurationException:"
+ pce.getMessage ());
}
return
doc;
}
/**
* creates an XML document (DOM) from the
data in the input file
* @param xmlFilename the input filename
containing the xml data
* @return Document the resulting DOM-tree
representation of xml
* data.
* @throws DocumentException. An exception
in case of failure of
* any of the steps involved in
* creating DOM-tree.
*/
public Document createDocument(String xmlFilename)
throws DocumentException
{
Document
doc = null;
try
{
// Create an instance of the DocumentBuilderFactory
DocumentBuilderFactory docBuilderFactory =
DocumentBuilderFactory.newInstance();
//Get DocumentBuilder from the factory we just got above.
DocumentBuilder docBuilder =
docBuilderFactory.newDocumentBuilder();
// turn it into an in-memory object
doc = docBuilder.parse(new File (xmlFilename));
}
catch
(ParserConfigurationException pce)
{
throw new DocumentException(
"ParserConfigurationException:"
+ pce.getMessage ());
}
catch
(SAXException saxe)
{
throw new DocumentException(
"ParserConfigurationException:"
+ saxe.getMessage ());
}
catch (IOException ioe)
{
throw new DocumentException(
"ParserConfigurationException:"
+ ioe.getMessage ());
}
return
doc;
}
/**
* Creates a clone of the input node. The
cloned node is inserted
*
in the DOM tree before the input node itself.
* @param node. The input node to be cloned.
*/
public void createCloneNode(Node node)
{
if (node != null)
{
Node
cnode = node.cloneNode(true);
node.getParentNode().insertBefore(cnode,
node);
}
}
/**
* Finds the text node available under the
input node.
* @param node. Input node.
* @return Text. The newly found text node
for the input node. It
* returns a null if the input node does not have
* any test node.
* @throws DocumentException. Throws exception
if the reference
*
element is null.
*/
public Text getTextNode(Node node) throws
DocumentException
{
if (node == null) {
throw
new DocumentException("Invalid/null input node.");
}
Text tnode = null;
NodeList children = node.getChildNodes();
for (int i = 0, nchildren = children.getLength();
i < nchildren;
i++)
{
Node
child = children.item(i);
if
(child.getNodeType() == Node.TEXT_NODE)
{
tnode
= (Text)child;
break;
}
}
return tnode;
}
public void deleteNodes(Vector nodes)
{
Iterator iter = nodes.iterator();
while (iter.hasNext())
{
Node node = (Node)iter.next();
node.getParentNode().removeChild(node);
}
}
}
Ramanand Singh is an Enterprise Java Architect with Nalanda Technology, Inc. He has over 14 years of experience in software industry. His focus has been on architecture, design, and implementation of enterprise applications using Object-Oriented technologies, design patterns, Java technology, CORBA technology, and J2EE technology. Mr. Singh was an invited guest speaker recently at IEEE Computer Society meeting for a presentation entitled “Building n-tier Enterprise Application using J2EE Platform.” He can be reached at rsingh@nalandatech.com.