This document describes a list of coding conventions that are required for code submissions to the project. By default, the coding conventions for most Open Source Projects should follow the existing coding conventions in the code that you are working on. For example, if the bracket is on the same line as the if statement, then you should write all your code to have that convention.
If you commit code that does not follow these conventions and you are caught, you are responsible for also fixing your own code.
Below is a list of coding conventions that are specific to gvSIG, everything else not specificially mentioned here should follow the official Sun Java Coding Conventions
As explained in the Sun Java Coding Conventions:
Code conventions are important to programmers for a number of reasons:
Headers
Look at the Headers document for more information.
Indentations
4 spaces. NO tabs.
Javadoc
All API interfaces must be fully documented through javadocs comments at interface, method and package level.
When you inherit or extend from another interface or class which is already documented, and implement or rewrite one of the parent methods, don't write any javadoc comments, as they are also inherited since java 1.4.
Brackets
All brackets should begin at the end of the line that begins the statement, and end on a new line indented to the beginning of the statement. Example:
AVOID:
public class MyClass
{
public void someMethod()
{
if (...) { // Do something }
}
}
RIGHT:
public class MyClass {
public void someMethod() {
if (...) {
// Do something
}
}
}
Brackets are mandatory even for single line statements:
if (expression) // AVOID!
// some code
if (expression) { // RIGHT
// some code
}
Class variables should not have any prefix or suffix related to its data type or scope. Example:
String nameString; // AVOID!
String name; // RIGHT
Avoid lines longer than 80 characters for Code, comments, ...
Logging
Do not use System.out to log. Instead, use the SLF4J logging API. For example:
private static final Logger LOG = LoggerFactory.getLogger(MyClass.class);
public void someMethod() {
LOG.debug("some debug text");
}
For more information on SLF4J usage, you can read the Logging section in this document.
Exception handling
Managing exceptions correctly requires experience. This is not supposed to be a guide on managing exceptions, simply a few best practices.
An example:
public void getTestClass() {
try {
Class responseClass =
Class.forName("some.package.MyClass");
} catch (ClassNotFoundException cnfe) {
String message = "Cannot instantiate test class";
LOG.warn(message, ex);
throw new ChainedRuntimeException(message, e);
}
}
Qualified imports
All import statements should containing the full class name of classes to import and should not use the "*" notation: An example:
// AVOID!
import java.util.*;
import java.net.*;
// RIGHT
import java.util.Date;
import java.net.HttpURLConnection;
Use interfaces in the declaration of methods and variables.
By example, if you need a variable x that is a list, declare it as List instead an ArrayList:
// AVOID!
ArrayList x = new ArrayList();
HashMap y = new HashMap();
public HashMap create(ArrayList keys, ArrarList values) {
...
}
// RIGHT
List x = new ArrayList();
Map y = new HashMap();
public Map create(List keys, List values) {
...
}
API packages
Usually, API interfaces and classes will belong to the library's main root package. If you create subpackages, use them to group by functionality, not by type.
How to name packages
All packages must begin with org.gvsig.
Normally,
the package is named org.gvsig followed,
a package name
that identifies the logical or
functional block will contain.
// AVOID !!!!! public static class MyPanel extends JPanel implements ActionListener { private void initComponents() { JButton btnOk = new JButton(); btnOk.addActionListener(this); } @Override public void actionPerformed(ActionEvent e) { ... } } // RIGHT public static class MyPanel extends JPanel { private void initComponents() { JButton btnOk = new JButton(); btnOk.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { btnOk_actionPerformed(); } }); } private void btnOk_actionPerformed() { } }
El uso de prefijos y/o sufijos en el nombre de clases e interfaces es normalmente una forma de aportar información sobre su naturaleza y/o cometido. Por ejemplo se pueden utilizar para denotar un patrón o un rol dentro de un patrón (por ejemplo el sufijo Factory). En otras ocasiones, se hace necesario su uso porque el nombre adecuado ya está asignado. Este es el caso de los prefijos y sufijos que se caracterizan a continuación.
Como regla general:
Ejemplo:
public interface List {}
public abstract class AbstractList extends AbstractCollection implements List {}
Se recomienda no utilizar.
Normalmente, las interfaces son la parte visible del modelo de un componente. Suelen representar a las entidades y conceptos propios del negocio o dominio y por tanto se recomienda mantener los nombres tal cual se utilizan en el negocio.
Ejemplo:
public interface ListModel {}
public abstract class AbstractListModel implements ListModel, Serializable {}
public class DefaultListModel extends AbstractListModel {}
Ejemplo:
public abstract class StreamRequestHandler {}
public class BaseHTTPRequestHandler extends StreamRequestHandler {}
Ejemplo:
public interface Plane {}
public abstract class AbstractPlane implements Plane {}
// Ambos son correctos (pero no iguales)
public class PlaneImpl implements Plane {}
public class PlaneImpl extends AbstractPlane {}
Este criterio se aplicará en los desarrollos que se realicen bajo el ambito de la Asociacion gvSIG o derivado de contratos realizados por esta.
Debido a la dispersión y falta de unidad en los nombres de paquetes que se han venido utilizando en gvSIG 1.X, se decidio uniformizarlos, dando una identidad de proyecto por encima del de la empresa que realiza el desarrollo.
A la hora de crear paquetes java que deban formar parte de una distribución oficial de gvSIG o vayan a llevar el respaldo oficial del proyecto gvSIG, estos colgarán del paquete:
org.gvsig
No haciendo mención en el paquete a la empresa que realiza el desarrollo.
Normalmente, el paquete se nombrará org.gvsig seguido, de un nombre de paquete que identifique el bloque lógico o funcional que va a contener.
Este criterio se aplicará en los desarrollos que se realicen bajo el ambito de la Asociacion gvSIG o derivado de contratos realizados por esta.
En gvSIG se emplea la librería SLF4J como API de logging a emplear.
SLF4J Simple Logging Facade o "Fachada de Registro Simple" es un framework que se ha creado para abstraer el sistema de registro que hay por debajo. Como el sistema de registro más popular usado es Log4j, el API del framework es muy similar para simplificar al máximo eliminar la dependencia directa de este sistema. Este framework por tanto es una capa de abstracción del sistema de registro, y nos va a permitir cambiar el componente de registro que lleve por debajo sin necesidad de un gran esfuerzo de recodificación de la aplicación.
// Those lines produce the same results. The second one has parameters that reduce the overhead when debuggin is disabled
LOG.debug("The new entry is "+entry+".");
LOG.debug("The new entry is {}.", entry);
gvSIG 2.0 ya está preparado para trabajar con SLF4J, usando LOG4J como implementación, por lo que podemos usarlo directamente desde cualquier extensión de gvSIG.
Para usar SLF4J desde una clase Java basta con incluir las siguientes sentencias:
1.- Importar las clases necesarias
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
2.- Declaramos e inicializamos el Logger.
public class MyClass
{
private static final Logger LOG = LoggerFactory.getLogger(MyClass.class);
...
3.- Usamos el Logger dentro del código de la clase, cuando queramos mostrar un mensaje de log, dependiendo del tipo: error, alerta, información, depuración o traza:
LOG.warn(String message);
LOG.warn(String message,Object arg1);
LOG.warn(String message,Object[] arg1);
LOG.warn(String message, Throwable arg1);
LOG.info(String message);
LOG.info(String message,Object arg1);
LOG.info(String message,Object[] arg1);
LOG.info(String message, Throwable arg1);
LOG.error(String message);
LOG.error(String message,Object arg1);
LOG.error(String message,Object[] arg1);
LOG.error(String message, Throwable arg1);
LOG.debug(String message);
LOG.debug(String message,Object arg1);
LOG.debug(String message,Object[] arg1);
LOG.debug(String message, Throwable arg1);
LOG.trace(String message);
LOG.trace(String message,Object arg1);
LOG.trace(String message,Object[] arg1);
LOG.trace(String message, Throwable arg1);
Los siguientes métodos se proporcionan para consultar la activación de los mensajes por nivel:
LOG.isErrorEnabled();
LOG.isWarnEnabled();
LOG.isInfoEnabled();
LOG.isDebugEnabled();
LOG.isTraceEnabled();
En SLF4J tenemos la capacidad adicional de parametrizar los mensajes, insertando variables dentro de la cadena String del mensaje de registro, como en el siguiente ejemplo:
private Integer temperature;
public void setTemperature(Integer temperature) {
LOG.debug("Setting temperature to {}. Old temperature was {}.", temperature, this.temperature);
this.temperature = temperature;
if(temperature.intValue() > 50) {
LOG.info("Temperature has risen above 50 degrees.");
}
}
Esto evita que tengamos que ir concatenando Strings, lo cuál reduce el coste del uso de las instrucciones de logging. Esto es debido a que, aunque el nivel de log que estemos usando esté desactivado (por ejemplo, el de debug), la invocación al método se hará de todas formas, incluyendo la concatenación de Strings para construir el mensaje, si la hubiera.
De todas formas, si la obtención de alguno de los parámetros que vamos a pasar al mensaje de log fuera costosa, es conveniente emplear los métodos de consulta para evitar dicha ejecución. Por ejemplo:
private Integer temperature;
public void setTemperature(Integer temperature) {
LOG.debug("Setting temperature to {}. Old temperature was {}.", temperature, this.temperature);
this.temperature = temperature;
addToTemperatureLog(temperature);
if (LOG.isDebugEnabled()) {
LOG.debug("The current average temperature is {} Celsius", calculateAverageTemperature());
}
}
XcolonX
":"
XsemicolonX
";"
XdotX
"."
XnlX
"\n"
XellipsisX
"..."
XquestionX
"?"
XexclamationX "!"
A la hora de crear interfaces de usuario, siempre que sea
posible, se utilizará la herramienta abeille.
Esta herramienta es adecuada para la creación de interfaces de
usuario de tipo formulario. Si el interface de usuario a crear
no es un formulario, no es preciso usar esta herramienta.
[ http://devel.gvsig.org/download/runtimes/abeille/
]
A la hora de crear los interfaces de usuario estos se guardarán
en formato xml junto a los ficheros fuente del proyecto. Además
se generará código java asociado al interface de usuario usando
el sufijo "View" para nombrar la clase java a generar. Estos ficheros
java generados nunca deberán ser editados. Para cada panel
se crearán dos o tres clases java. Vamos a ver esto con un
ejemplo. Supongamos que estamos creando el panel "general"
de propiedades de una capa. Tendremos:
A la hora de crear el interface de usuario deberemos de tener
en cuenta:
A la hora de crear la clase "controller", tendremos en cuenta:
Estas consideraciones estan relacionadas con la implementación
de paneles y cuadros de diálogo. Normalmente estos llevaran
asociada en el API un interface definiendo el API del panel, que
deberá estar implememtado con la clase "controller". Desde fuera
de la implementación no se deberá acceder nunca a los
componentes del interface de usuario, debiendo existir métodos
para asignar los valores de entrada del formulario y recoger los
de salida. Si estos métodos se limitan a hacer get y set sobre
los componentes del formulario, revisa el análisis, es fácil que
hayas trasladado al cliente del panel responsabilidades del
"controller".
Siempre que precisemos acceder al documento vista y no al
interface gráfico, en
lugar de recuperar el documento a partir de la ventana activa,
usaremos el método
getActiveDocument del ApplicationManager.
Haríamos algo como:
ApplicationManager application = ApplicationLocator.getManager();
ViewDocument doc = (ViewDocument) application.getActiveDocument(ViewManager.TYPENAME);
if( doc == null ) {
return false;
}
MapContext mapContext = doc.getMapContext();
Asi mismo, si una vez recuperado el documento vista debemos
determinar si contiene capas vectoriales, o contiene capas
vectoriales activas usaremos los metodos del MapContext:
Por ejemplo:
return mapContext.hasActiveVectorLayers();