Anchor(CodingGuidelinesJavaRelated)

title(Coding Guideline)

Action(edit)

TableOfContents(3)

1. Introduction

This guideline gives some recommendations for those who want to adapt the current code and/or send in new plugins. They should be regarded as recommendations, not rules, but following them will make life easier for both parties.

Furthermore it gives guidelines for how to adapt the current code to the design that are already decided and used in the NetarchiveSuite software. This relates to the design described in the ["System Design"] document.

Guidelines on Unit tests can be found in

2. Java Related

2.1. Coding style

Our overall coding style is based on [http://java.sun.com/docs/codeconv/html/CodeConvTOC.doc.html Sun's guidelines] with the following extensions:

2.1.1. Unit Tests

All code must be covered as much as possible in unit tests. Please refer to [:Guidelines/Unit Test Guideline:unit test guideline] for more information.

2.1.2. Nested class definitions

Declare nested classes as static whenever possible. This avoids an unnecessary link back to the outer class, and in particular makes it possible to serialized the inner class even if the outer class is not serializable. The "invisible" link to the outer class found in a non-static inner class can also lead to unexpected memory leaks, as an inner instance may outlive its outer instance and keep it artificially alive through its implicit link. Nested class definitions appear at the beginning of the enclosing class before (static) variables.

Example:

class A {
    public static B {
        // B stuff
    }
    public static Integer ACONST=42;
    ...
}

2.1.3. Variable declarations

The general rule is "put declarations only at the beginning of blocks". We allow one exception from this rule, namely declarations that 1) initialize the variable and 2) depend on previous calculations are allowed be further down the block. Example:

void Foo() {
int i1=42;
int i2=0;
i2 = f(i1);
int i3 = g(i2);
}

2.1.4. Miscellaneous

Don't use * import statements, it clutters up the namespace and makes it hard to see what is intended. Good IDEs can do your imports automatically anyway.

Tabs should never be used in the source files. Most editors can use spaces instead.

Public methods should always check that their arguments follow the JavaDoc restriction with respect to being null, empty, non-negative etc. The ArgumentNotValid class has a number of useful methods for this.

JavaDoc is strongly encouraged, as the code might explain what happens, but not the why; the JavaDoc must describe the intent of the function, including assumptions and invariants as well as expectations of the arguments.

2.2. Exceptions

At the outset of the project, we decided to use undeclared exceptions throughout our code to avoid to avoid cluttering method definitions with exceptions that are merely passing through, and to have more flexibility in what exceptions can be thrown in subclasses and interface implementations. Before you argue this decision, please read the [http://www-106.ibm.com/developerworks/java/library/j-jtp05254.html arguments] [http://www.mindview.net/Books/TIJ/ for] and [http://www.artima.com/intv/solid.html against]. Notice that the fact that an exception is unchecked does not mean that you don't need to document its usage in JavaDoc for your methods, and you can still add it to the throws clause.

At any point where exceptions enter our code, we catch them and either handle them immediately or throw one of our exceptions instead, with the caught exception as the cause. All our exceptions inherit from dk.netarkivet.common.exceptions.NetarkivetException, and we try to keep the number of exceptions at a minimum. At the moment, the following exceptions exist:

One standard example of how to catch outside exceptions and handle resource freeing is:

    InputStream in;
    try {
        try {
            in = new FileInputStream(file);
            in.readAll(...);
        } finally {
            if (in != null) {
                in.close();
            }
        }
    } catch (IOException e) {
        throw new IOFailure("Failed to read file '" + file + "'", e);
    }

Notice how the error message contains the file name in quotes (makes it easier to understand empty file error), and how the IOFailure gets the original exception passed in -- it is very important to never let the original exception vanish.

When it comes to handling our internal exceptions, the general rule is: Avoid catching exceptions unless you need to catch it. Also expressed as "Never catch an exception that you do not know how to handle" (with apologies to H. P. Lovecraft).

You need to catch an internal exception if:

2.3. Logging

We use the apache.commons.logging framework for logging, which gives us one unified interface that can be realized with different underlying systems.

However, currently the monitoring component requires the underlying implementation to be Jdk14 logging, since it exposes log messages using a LogHandler implementation for the Jdk14 framework. To use another logging framework, this method would need to be redefined for that framework (for instance an appender for Log4J).

3. Design Related

The following is to be split between the [System Design] document and this document, so that coding guidelines of how to code according to this design is put here, while description of how the design works is put into the [System Design] document.

Include(Developer Manual devel/Coding Guidelines - Design Related)