02 - Development

These pages only relate to developing Across and the standard modules. To use Across as a framework or the modules, please refer to /wiki/spaces/AX/pages/12648466.

Important locations

Development guidelines

Helping out

If you feel like helping out on the core or any of the standard modules, you can find a list of open issues on Bitbucket.

Just fork the bitbucket repository, make your changes and then launch a pull request.

General conventions

Module settings

If a module supports properties, these should preferably be listed as static fields on a settings class.  The settings class should be in the same package as the module descriptor, and have the same class name with Settings as a suffix.  Example: AdminWebModule defines the possible properties in AdminWebModuleSettings

Integration and unit tests

To optimize the builds, a clean separation should be made between unit tests and integration tests, even though both are implemented using JUnit.

For more information on integration tests and testing modules in general, see the Integration tests page.

Data layers and test data

When building a persistence layer in your module, you should try to follow these conventions:

  • an id of 0 (primitive) means the entity has not been persisted to the database
  • all other ids (both positive and negative) should be allowed
  • auto generated ids should always be larger than 0
  • the id range below zero should be available for providing test data
  • your service layer should support creating new entities with a predefined id (eg. using a isNewEntity like property on a DTO)
    • an example of this can be found on the UserDto implementation in the UserModule

Database support

Standard modules should support the folllowing databases:

  • HSQLDB
  • MySQL 5+
  • Oracle 11G+
  • SQL Server 2008+

This usually means installers (mostly Liquibase) should take this into account.

Tips for Liquibase changesets

With Liquibase you can provide multiple changesets for different dbms, but with some care you can reuse the same changeset.

Preconditions and MARK_RAN

By providing preconditions on your changeset and marking the changeset as ran if the precondition fails you make it easier and safer for the same changesets to be run multiple times.

 <changeSet id="201406121322" author="arne">
	<preConditions onFail="MARK_RAN">
		<not>
			<tableExists tableName="ACROSS_SEQUENCES"/>
		</not>
	</preConditions>
	<comment>Comments must be after the preConditions element!</comment>
	...
</changeSet>
Defining primary keys

Define the primary key directly on the column definition of a createTable, instead of a separate addPrimaryKey statement.  Also make the column explicitly not nullable.  In both cases this improves compatibility for SQL Server.

When using strings as primary key, limit the key length to 255 characters. The reason for this is MySQL default settings for index key length (767 bytes on InnoDB for UTF-8), see the MySQL documentation.

Key names

When specifying key names (index, foreign key etc), limit the length to 30 characters (maximum supported by Oracle).

Java SQL types

When specifying a column data type, use the java.sql.Types.* support as this converts to the corresponding dbms specific type.

<createTable tableName="MYTABLE">
	<column name="id" type="java.sql.Types.BIGINT">
		<constraints nullable="false" primaryKey="true" />
	</column>
	<column name="username" type="java.sql.Types.VARCHAR(255)" />
	<column name="unicode_text" type="java.sql.Types.NVARCHAR(1000)" />
	<column name="created" type="java.sql.Types.TIMESTAMP" />
</createTable> 
Oracle (var)char length

Oracle supports (var)char length in bytes or characters.  The default depends on the database configuration.  In most cases you will want the length specified in characters.  Instead of having to provide the char specifier - which is not supported by most other dbms - you can use the conversion from the Java SQL types by specifying nls_length_semantics in your session.

You can easily do this by adding a separate changeset that always runs to your script.

<changeSet id="123456" author="..." runAlways="true" dbms="oracle">
	<sql>
		ALTER SESSION SET NLS_LENGTH_SEMANTICS=CHAR;
	</sql>
</changeSet>