deegree3 IDE settings and coding practices
This page documents common IDE settings and practices for deegree 3 core developers.
1. Eclipse Settings
As most settings are the same for deegree2 and deegree3, please refer to the description at Eclipse#HowToConfigureEclipse.
1.1. Eclipse compiler settings
Todo: add description
1.2. Eclipse code style (code templates and formatter)
deegree source code uses a customized coding style, consisting of headers, comment styles, specific indentation, etc. These settings are defined in Eclipse.
1.3. SVN templates to be used
At the moment there are no deegree3-specific commit templates. Therefore please refer to Eclipse/CommitTemplates.
2. Coding Practices
2.1. Logging
In deegree 3, we're usually using log4j for logging (through slf4j). It is generally a nice thing to have a 'template' log4j.properties, where the important classes are listed together with a description what is logged on which level, like this:
# logs very important information #log4j.logger.org.deegree.services.wms.MostImportantClass=TRACE # logs the most important information #log4j.logger.org.deegree.services.wms.MostImportantClass=DEBUG
This information is now generated automatically using annotations. You can annotate a class using the LoggingNotes annotation, like this:
@LoggingNotes(debug = "logs the most important information", trace = "logs very important information")
public class MostImportantClass {
...
You can optionally set the text for warn, info, error, debug and trace, corresponding to the log level of the same name. The above annotation will generate exactly the log4j.properties snippet as shown (speling mistakes which I integrated are excluded).
2.1.1. Package logging
For packages, we have the PackageLoggingNotes. These can be used to generate a section header, and to generate package level descriptions as shown above. So additionally, you have the (optional) title parameter for the annotation. To make a package level annotation, create a new package-info.java file in your package, with content like this:
@PackageLoggingNotes(title = "the WMS section", debug = "logs debugging stuff", warn = "logs possible problems")
package org.deegree.services.wms;
2.1.2. Making actual use of it
To generate a useful log4j.properties template, you'll have to check out d3_core and d3_services. Edit the build.properties as appropriate, and run the ant target make-log4j.properties in d3_services. This will give you a proper log4j.properties in d3_services/build/.
2.2. XMLStreamWriter
XMLStreamReader and XMLStreamWriter are used heavily in deegree 3 for processing streams of XML. Special care has to be taken in order to use XMLStreamWriter in a way that is compatible with different StaX implementations (e.g. bundled versions with JDK, Woodstox, StaX implementation on Oracle Weblogic). Problems occur when dealing with qualified element/attribute names and binding namespaces.
Best practices:
See http://ws.apache.org/axiom/devguide/ch03.html for more info on established usage patterns for XMLStreamWriter. All deegree code should follow usage pattern 3.
Don't set javax.xml.stream.isRepairingNamespaces to true when creating the XMLStreamWriter. It may look like a good idea for easing the task of binding namespaces and catching unbound namespaces, but it turned out that the introduced behaviour differs between different StaX-implementations and it is makes it hard to detect possible errors. Without it, you have to call XMLStreamWriter.writeNamespace(String prefix, String uri) manually, but at least a dependable behavior is achieved among implementations.
Understand that (in non-repairing mode) XMLStreamWriter.setPrefix(String prefix, String uri) only makes a namespace binding known to the XMLStreamWriter instance, but does not actually write xmlns:prefix="namespace" to the stream. XMLStreamWriter.writeNamespace(String prefix, String uri) writes xmlns:prefix="namespace" to the stream (and makes the binding known as well).
Using XMLStreamWriter.write (String namespaceURI, String localName) should be preferred over XMLStreamWriter.write (String prefix, String localName, String namespaceURI), as it eases the task of changing the prefix (and avoids redundancy in general). Only use XMLStreamWriter.write (String prefix,String localName,String namespaceURI) in case an element needs to be written that has a namespace that may be unbound at this point.
There's a special issue with writeEmptyElement(...). The problem is that the local bindings for this element are kept after the empty element has been written. Apparently, StaX must do so in order to allow writing of (qualified) attributes. In order to make the namespace context forget the local bindings, writer.writeCharacters( "" ); seems to do the trick.