1. Project

1.1. Building

The Codion framework is built with Gradle and includes the Gradle Wrapper with a toolchain defined, so assuming you have cloned the repository and worked your way into the project directory you can build the framework by running the following command.

gradlew build
Note
This may take a few minutes, depending on the machine.

To install the Codion framework into your local Maven repository run the following command.

gradlew publishToMavenLocal

1.2. Running the demos

Note
The demos use an embedded in-memory database, so changes to data do not persist.

1.2.1. Local database connection

You can start by running a client from one of the demo projects (employees, chinook, petstore or world) with a local database connection.

gradlew codion-demos-chinook:runClientLocal

1.2.2. Remote database connection

In order to run a client with a remote or http connection the remote server must be started first.

gradlew codion-framework-server:runServer

To run a demo client with a remote connection use the following command.

gradlew codion-demos-chinook:runClientRMI

You can run the Server Monitor application to see how the server is behaving, with the following command.

gradlew codion-swing-framework-server-monitor:runServerMonitor
Note
The client handles server restarts gracefully, you can try shutting down the server via the Server Monitor, play around in the client until you get a 'Connection refused' exception. After you restart the server the client simply reconnects and behaves as if nothing happened.

1.3. Code quality

2. Architecture

The Codion framework is based on a three tiered architecture.

  • Database layer

  • Model layer

  • UI layer

2.1. Database layer

The EntityConnection class defines the database layer. See Manual:EntityConnection

2.2. Model layer

The EntityModel class defines the model layer. See Manual:EntityModel.

2.3. UI layer

The EntityPanel class defines the UI layer. See Manual:EntityPanel.

3. Client

3.1. Features

  • Lightweight client with a simple synchronous event model

  • Provides a practically mouse free user experience

  • Graceful handling of network outages and server restarts

  • Clear separation between model and UI

  • Easy to use load testing harness provided for application models

  • UI data bindings for most common components provided by the framework

  • Implementing data bindings for new components is made simple with building blocks provided by the framework.

  • The default UI layout is a simple and intuitive “waterfall” master-detail view

  • Extensive searching and filtering capabilities

  • Flexible keyboard-centric UI based on tab and split panes, detachable panels and toolbars

  • Detailed logging of client actions

3.2. Default client layout

The default master/detail panel layout.

Client UI

3.3. Architecture

3.3.1. UI

ui architecture

3.3.2. Model

model architecture

3.3.3. Assembly

EntityModel
  /**
   * Creates a SwingEntityModel based on the {@link Artist#TYPE} entity
   * with a detail model based on {@link Album#TYPE}
   * @param connectionProvider the connection provider
   */
  static SwingEntityModel artistModel(EntityConnectionProvider connectionProvider) {
    // create a default edit model
    SwingEntityEditModel artistEditModel =
            new SwingEntityEditModel(Artist.TYPE, connectionProvider);

    // create a default table model, wrapping the edit model
    SwingEntityTableModel artistTableModel =
            new SwingEntityTableModel(artistEditModel);

    // create a default model wrapping the table model
    SwingEntityModel artistModel =
            new SwingEntityModel(artistTableModel);

    // Note that this does the same as the above, that is, creates
    // a SwingEntityModel with a default edit and table model
    SwingEntityModel albumModel =
            new SwingEntityModel(Album.TYPE, connectionProvider);

    artistModel.addDetailModel(albumModel);

    return artistModel;
  }
EntityPanel
  /**
   * Creates a EntityPanel based on the {@link Artist#TYPE} entity
   * with a detail panel based on {@link Album#TYPE}
   * @param connectionProvider the connection provider
   */
  static EntityPanel artistPanel(EntityConnectionProvider connectionProvider) {
    // create the EntityModel to base the panel on (calling the above method)
    SwingEntityModel artistModel = artistModel(connectionProvider);

    // the edit model
    SwingEntityEditModel artistEditModel = artistModel.editModel();

    // the table model
    SwingEntityTableModel artistTableModel = artistModel.tableModel();

    // the album detail model
    SwingEntityModel albumModel = artistModel.detailModel(Album.TYPE);

    // create a EntityEditPanel instance, based on the artist edit model
    EntityEditPanel artistEditPanel = new EntityEditPanel(artistEditModel) {
      @Override
      protected void initializeUI() {
        createTextField(Artist.NAME).columns(15);
        addInputPanel(Artist.NAME);
      }
    };
    // create a EntityTablePanel instance, based on the artist table model
    EntityTablePanel artistTablePanel = new EntityTablePanel(artistTableModel);

    // create a EntityPanel instance, based on the artist model and
    // the edit and table panels from above
    EntityPanel artistPanel = new EntityPanel(artistModel, artistEditPanel, artistTablePanel);

    // create a new EntityPanel, without an edit panel and
    // with a default EntityTablePanel
    EntityPanel albumPanel = new EntityPanel(albumModel);

    artistPanel.addDetailPanel(albumPanel);

    return artistPanel;
  }

3.3.4. Full Example

Show code
package is.codion.framework.demos.chinook.tutorial;

import is.codion.common.db.database.Database;
import is.codion.common.user.User;
import is.codion.framework.db.EntityConnectionProvider;
import is.codion.framework.db.local.LocalEntityConnectionProvider;
import is.codion.framework.demos.chinook.domain.Chinook.Album;
import is.codion.framework.demos.chinook.domain.Chinook.Artist;
import is.codion.framework.demos.chinook.domain.impl.ChinookImpl;
import is.codion.swing.framework.model.SwingEntityEditModel;
import is.codion.swing.framework.model.SwingEntityModel;
import is.codion.swing.framework.model.SwingEntityTableModel;
import is.codion.swing.framework.ui.EntityEditPanel;
import is.codion.swing.framework.ui.EntityPanel;
import is.codion.swing.framework.ui.EntityTablePanel;

/**
 * When running this make sure the chinook demo module directory is the
 * working directory, due to a relative path to a db init script
 */
public final class ClientArchitecture {

  // tag::entityModel[]
  /**
   * Creates a SwingEntityModel based on the {@link Artist#TYPE} entity
   * with a detail model based on {@link Album#TYPE}
   * @param connectionProvider the connection provider
   */
  static SwingEntityModel artistModel(EntityConnectionProvider connectionProvider) {
    // create a default edit model
    SwingEntityEditModel artistEditModel =
            new SwingEntityEditModel(Artist.TYPE, connectionProvider);

    // create a default table model, wrapping the edit model
    SwingEntityTableModel artistTableModel =
            new SwingEntityTableModel(artistEditModel);

    // create a default model wrapping the table model
    SwingEntityModel artistModel =
            new SwingEntityModel(artistTableModel);

    // Note that this does the same as the above, that is, creates
    // a SwingEntityModel with a default edit and table model
    SwingEntityModel albumModel =
            new SwingEntityModel(Album.TYPE, connectionProvider);

    artistModel.addDetailModel(albumModel);

    return artistModel;
  }
  // end::entityModel[]
  // tag::entityPanel[]
  /**
   * Creates a EntityPanel based on the {@link Artist#TYPE} entity
   * with a detail panel based on {@link Album#TYPE}
   * @param connectionProvider the connection provider
   */
  static EntityPanel artistPanel(EntityConnectionProvider connectionProvider) {
    // create the EntityModel to base the panel on (calling the above method)
    SwingEntityModel artistModel = artistModel(connectionProvider);

    // the edit model
    SwingEntityEditModel artistEditModel = artistModel.editModel();

    // the table model
    SwingEntityTableModel artistTableModel = artistModel.tableModel();

    // the album detail model
    SwingEntityModel albumModel = artistModel.detailModel(Album.TYPE);

    // create a EntityEditPanel instance, based on the artist edit model
    EntityEditPanel artistEditPanel = new EntityEditPanel(artistEditModel) {
      @Override
      protected void initializeUI() {
        createTextField(Artist.NAME).columns(15);
        addInputPanel(Artist.NAME);
      }
    };
    // create a EntityTablePanel instance, based on the artist table model
    EntityTablePanel artistTablePanel = new EntityTablePanel(artistTableModel);

    // create a EntityPanel instance, based on the artist model and
    // the edit and table panels from above
    EntityPanel artistPanel = new EntityPanel(artistModel, artistEditPanel, artistTablePanel);

    // create a new EntityPanel, without an edit panel and
    // with a default EntityTablePanel
    EntityPanel albumPanel = new EntityPanel(albumModel);

    artistPanel.addDetailPanel(albumPanel);

    return artistPanel;
  }
  // end::entityPanel[]

  public static void main(String[] args) {
    // Configure the database
    Database.DATABASE_URL.set("jdbc:h2:mem:h2db");
    Database.DATABASE_INIT_SCRIPTS.set("src/main/sql/create_schema.sql");

    // initialize a connection provider, this class is responsible
    // for supplying a valid connection or throwing an exception
    // in case a connection can not be established
    EntityConnectionProvider connectionProvider =
            LocalEntityConnectionProvider.builder()
                    .domain(new ChinookImpl())
                    .user(User.parse("scott:tiger"))
                    .build();

    EntityPanel artistPanel = artistPanel(connectionProvider);

    // lazy initialization
    artistPanel.initialize();

    // fetch data from the database
    artistPanel.model().tableModel().refresh();

    // uncomment the below line to display the panel
//    displayInDialog(null, artistPanel, "Artists");

    connectionProvider.close();
  }
}

3.4. Configuration

3.4.1. Example configuration file

codion.client.connectionType=local
codion.db.url=jdbc:h2:mem:h2db
codion.db.initScripts=classpath:create_schema.sql

3.5. Usage

4. Server

The Codion server provides RMI and HTTP connection options to clients.

4.1. Features

  • Firewall friendly RMI; uses one way communications without callbacks and can be configured to serve on a single fixed port

  • Integrated web server for serving HTTP client connections, based on Javalin and Jetty

  • All user authentication left to the database by default

  • Comprehensive administration and monitoring facilities via the ServerMonitor

  • Featherweight server with moderate memory and CPU usage

4.2. Security

Here’s a great overview of RMI security risks and mitigations.

4.2.1. Authentication

The Codion server does not perform any user authentication by default, it leaves that up the underlying database. An authentication layer can be added by implementing a Authenticator and registering it with the ServiceLoader.

Authenticator examples

4.2.2. RMI SSL encryption

To enable SSL encryption between client and server, create a keystore and truststore pair and set the following system properties.

Server side
codion.server.connection.sslEnabled=true # (1)
javax.net.ssl.keyStore=keystore.jks
javax.net.ssl.keyStorePassword=password
  1. This property is 'true' by default, included here for completenes’s sake

Client side
codion.client.trustStore=truststore.jks
codion.client.trustStorePassword=password

4.2.3. Class loading

No dynamic class loading is required.

4.2.4. Serialization whitelist

A serialization whitelist can be used by setting the following system property.

codion.server.serializationFilterWhitelist=config/whitelist.txt

A whitelist can be created during a server dry-run by adding the following system property. The whitelist containing all classes deserialized during the run is written to disk on server shutdown.

codion.server.serializationFilterDryRun=true
Example whitelist
[B
[C
[Lis.codion.framework.domain.entity.attribute.Attribute;
[Lis.codion.framework.domain.entity.attribute.Column;
[Ljava.lang.Object;
[Ljava.lang.String;
[Ljava.util.Map$Entry;
[Lnet.sf.jasperreports.engine.JRBand;
[Lnet.sf.jasperreports.engine.JRExpressionChunk;
[Lnet.sf.jasperreports.engine.JRField;
[Lnet.sf.jasperreports.engine.JRParameter;
[Lnet.sf.jasperreports.engine.JRQueryChunk;
[Lnet.sf.jasperreports.engine.JRVariable;
ch.qos.logback.classic.Level
com.sun.proxy.$Proxy*
java.lang.Boolean
java.lang.Character
java.lang.Double
java.lang.Enum
java.lang.Float
java.lang.Integer
java.lang.Long
java.lang.Number
java.lang.String
java.lang.reflect.Proxy
java.math.BigDecimal
java.math.BigInteger
java.time.LocalDate
java.time.LocalDateTime
java.time.LocalTime
java.time.Ser
java.time.ZoneId
java.time.ZoneRegion
java.util.ArrayList
java.util.Arrays$ArrayList
java.util.Collections$EmptyList
java.util.Collections$EmptyMap
java.util.Collections$SingletonList
java.util.Collections$SingletonMap
java.util.Collections$UnmodifiableCollection
java.util.Collections$UnmodifiableList
java.util.Collections$UnmodifiableMap
java.util.Collections$UnmodifiableSet
java.util.Collections$UnmodifiableRandomAccessList
java.util.Date
java.util.HashMap
java.util.HashSet
java.util.LinkedHashMap
java.util.LinkedHashSet
java.util.Locale
java.util.UUID
net.sf.jasperreports.compilers.ConstantExpressionEvaluation
net.sf.jasperreports.compilers.FieldEvaluation
net.sf.jasperreports.compilers.ReportExpressionEvaluationData
net.sf.jasperreports.engine.JRPropertiesMap
net.sf.jasperreports.engine.JasperReport
net.sf.jasperreports.engine.base.JRBaseBand
net.sf.jasperreports.engine.base.JRBaseBoxBottomPen
net.sf.jasperreports.engine.base.JRBaseBoxLeftPen
net.sf.jasperreports.engine.base.JRBaseBoxPen
net.sf.jasperreports.engine.base.JRBaseBoxRightPen
net.sf.jasperreports.engine.base.JRBaseBoxTopPen
net.sf.jasperreports.engine.base.JRBaseDataset
net.sf.jasperreports.engine.base.JRBaseElement
net.sf.jasperreports.engine.base.JRBaseElementGroup
net.sf.jasperreports.engine.base.JRBaseExpression
net.sf.jasperreports.engine.base.JRBaseExpressionChunk
net.sf.jasperreports.engine.base.JRBaseField
net.sf.jasperreports.engine.base.JRBaseLineBox
net.sf.jasperreports.engine.base.JRBaseParagraph
net.sf.jasperreports.engine.base.JRBaseParameter
net.sf.jasperreports.engine.base.JRBasePen
net.sf.jasperreports.engine.base.JRBaseQuery
net.sf.jasperreports.engine.base.JRBaseQueryChunk
net.sf.jasperreports.engine.base.JRBaseReport
net.sf.jasperreports.engine.base.JRBaseSection
net.sf.jasperreports.engine.base.JRBaseStaticText
net.sf.jasperreports.engine.base.JRBaseTextElement
net.sf.jasperreports.engine.base.JRBaseTextField
net.sf.jasperreports.engine.base.JRBaseVariable
net.sf.jasperreports.engine.design.JRReportCompileData
net.sf.jasperreports.engine.type.CalculationEnum
net.sf.jasperreports.engine.type.EvaluationTimeEnum
net.sf.jasperreports.engine.type.HorizontalTextAlignEnum
net.sf.jasperreports.engine.type.IncrementTypeEnum
net.sf.jasperreports.engine.type.OrientationEnum
net.sf.jasperreports.engine.type.PositionTypeEnum
net.sf.jasperreports.engine.type.PrintOrderEnum
net.sf.jasperreports.engine.type.ResetTypeEnum
net.sf.jasperreports.engine.type.RunDirectionEnum
net.sf.jasperreports.engine.type.SectionTypeEnum
net.sf.jasperreports.engine.type.SplitTypeEnum
net.sf.jasperreports.engine.type.StretchTypeEnum
net.sf.jasperreports.engine.type.TextAdjustEnum
net.sf.jasperreports.engine.type.WhenResourceMissingTypeEnum
is.codion.common.Conjunction
is.codion.common.Operator
is.codion.common.db.operation.DefaultFunctionType
is.codion.common.db.operation.DefaultProcedureType
is.codion.common.db.report.AbstractReport
is.codion.common.db.report.DefaultReportType
is.codion.common.rmi.client.DefaultConnectionRequest
is.codion.common.user.DefaultUser
is.codion.common.version.DefaultVersion
is.codion.framework.db.DefaultSelect
is.codion.framework.db.DefaultUpdate
is.codion.framework.domain.DefaultDomainType
is.codion.framework.domain.entity.attribute.DefaultAttribute
is.codion.framework.domain.entity.attribute.DefaultAttribute$DefaultType
is.codion.framework.domain.entity.attribute.DefaultColumn
is.codion.framework.domain.entity.attribute.DefaultForeignKey
is.codion.framework.domain.entity.attribute.DefaultForeignKey$DefaultReference
is.codion.framework.domain.entity.condition.AbstractCondition
is.codion.framework.domain.entity.condition.AbstractColumnCondition
is.codion.framework.domain.entity.condition.DefaultAllCondition
is.codion.framework.domain.entity.condition.DefaultConditionCombination
is.codion.framework.domain.entity.condition.DefaultCustomCondition
is.codion.framework.domain.entity.condition.AbstractColumnCondition
is.codion.framework.domain.entity.condition.DualValueColumnCondition
is.codion.framework.domain.entity.condition.MultiValueColumnCondition
is.codion.framework.domain.entity.condition.SingleValueColumnCondition
is.codion.framework.domain.entity.condition.DefaultConditionType
is.codion.framework.domain.entity.DefaultEntity
is.codion.framework.domain.entity.DefaultEntity$EntityInvoker
is.codion.framework.domain.entity.DefaultEntityType
is.codion.framework.domain.entity.DefaultForeignKey
is.codion.framework.domain.entity.DefaultForeignKey$DefaultReference
is.codion.framework.domain.entity.DefaultKey
is.codion.framework.domain.entity.DefaultOrderBy
is.codion.framework.domain.entity.DefaultOrderBy$DefaultOrderByColumn
is.codion.framework.domain.entity.Entity
is.codion.framework.domain.entity.ImmutableEntity
is.codion.framework.domain.entity.OrderBy$NullOrder
is.codion.framework.demos.chinook.domain.Chinook
is.codion.framework.demos.chinook.domain.Chinook$Invoice
is.codion.framework.demos.chinook.domain.Chinook$Playlist$RandomPlaylistParameters
is.codion.framework.demos.chinook.domain.Chinook$Track
is.codion.framework.demos.chinook.domain.Chinook$Track$RaisePriceParameters
is.codion.framework.demos.employees.domain.*
is.codion.framework.demos.world.domain.api.*
is.codion.framework.demos.petclinic.domain.*
is.codion.plugin.jasperreports.DefaultJRReportType

4.3. Configuration

4.3.1. Example configuration file

# Database configuration
codion.db.url=jdbc:h2:mem:h2db
codion.db.useOptimisticLocking=true
codion.db.initScripts=\
    ../config/employees/create_schema.sql,\
    ../config/chinook/create_schema.sql,\
    ../config/petstore/create_schema.sql,\
    ../config/world/create_schema.sql

# The admin user credentials, used by the server monitor application
codion.server.admin.user=scott:tiger

# Client logging disabled by default
codion.server.clientLogging=false

# A connection pool based on this user is created on startup
codion.server.connectionPoolUsers=scott:tiger

# The port used by clients
codion.server.port=2222

# The port for the admin interface, used by the server monitor
codion.server.admin.port=4444

# RMI Registry port
codion.server.registryPort=1099

# Any auxiliary servers to run alongside this server
codion.server.auxiliaryServerFactoryClassNames=\
    is.codion.framework.servlet.EntityServletServerFactory

# The http port
codion.server.http.port=8080

# Specifies whether or not to use https
codion.server.http.secure=false

# The serialization whitelist to use for RMI deserialization
codion.server.serializationFilterWhitelist=\
    ../config/serialization-whitelist.txt

# RMI configuration
java.rmi.server.hostname=localhost
java.rmi.server.randomIDs=true

# SSL configuration
javax.net.ssl.keyStore=../config/keystore.jks
javax.net.ssl.keyStorePassword=crappypass

# Used to connect to the server to shut it down
#codion.client.trustStore=../config/truststore.jks
#codion.client.trustStorePassword=crappypass

4.4. Code examples

Absolute bare-bones examples of how to run the EntityServer and connect to it.

4.4.1. RMI

    Database database = H2DatabaseFactory
            .createDatabase("jdbc:h2:mem:testdb",
                    "src/main/sql/create_schema.sql");

    EntityServerConfiguration configuration = EntityServerConfiguration.builder(SERVER_PORT, REGISTRY_PORT)
            .domainClassNames(singletonList(Store.class.getName()))
            .database(database)
            .sslEnabled(false)
            .build();

    EntityServer server = EntityServer.startServer(configuration);

    RemoteEntityConnectionProvider connectionProvider =
            RemoteEntityConnectionProvider.builder()
                    .port(SERVER_PORT)
                    .registryPort(REGISTRY_PORT)
                    .domainType(Store.DOMAIN)
                    .user(parse("scott:tiger"))
                    .clientTypeId("ClientServer")
                    .build();

    EntityConnection connection = connectionProvider.connection();

    List<Entity> customers = connection.select(all(Customer.TYPE));
    customers.forEach(System.out::println);

    connection.close();

    server.shutdown();

4.4.2. HTTP

    Database database = H2DatabaseFactory
            .createDatabase("jdbc:h2:mem:testdb",
                    "src/main/sql/create_schema.sql");

    EntityService.HTTP_SERVER_PORT.set(HTTP_PORT);

    EntityServerConfiguration configuration = EntityServerConfiguration.builder(SERVER_PORT, REGISTRY_PORT)
            .domainClassNames(singletonList(Store.class.getName()))
            .database(database)
            .sslEnabled(false)
            .auxiliaryServerFactoryClassNames(singletonList(EntityServiceFactory.class.getName()))
            .build();

    EntityServer server = EntityServer.startServer(configuration);

    HttpEntityConnectionProvider connectionProvider =
            HttpEntityConnectionProvider.builder()
                    .port(HTTP_PORT)
                    .https(false)
                    .domainType(Store.DOMAIN)
                    .user(parse("scott:tiger"))
                    .clientTypeId("ClientServer")
                    .build();

    EntityConnection connection = connectionProvider.connection();

    List<Entity> customers = connection.select(all(Customer.TYPE));
    customers.forEach(System.out::println);

    connection.close();

    server.shutdown();

5. Server Monitor

The Codion Server Monitor provides a way to monitor the Codion server.

Below are screenshots of the different server monitor tabs, after ~1 1/2 hours of running the Chinook load test, with ~10 minutes of ramping up to 100 client instances. The server is running on a Raspberry Pi 4, Ubuntu Server 20.10, JDK 19, -Xmx256m, using a HikariCP connection pool on top of an H2 in-memory database.

5.1. Server performance

Server performance

5.2. Connection pools

Connection pool

5.3. Database performance

Database performance

5.4. Clients & users

Clients users

5.5. Environment

5.5.1. System

System

5.5.2. Entities

Domain

5.5.3. Operations

Domain

6. Code style and design

6.1. Factories and builders

Most concrete framework classes, which implement a public interface, are final, package private, and are instantiated with the help of static methods in the interface they implement.

6.1.1. Factories

Static factory methods are provided for classes with a simple initial state. These are usually named after the interface, which makes using static imports quite convenient.

Event<String> event = event(); // Event.event()

Value<Integer> value = value(42); // Value.value()

State state = state(true); // State.state()

EntityTableConditionModel<Attribute<?>> conditionModel =
        entityTableConditionModel(Customer.TYPE, connectionProvider);

6.1.2. Builders

For classes with a more complex initial state, a builder method is provided in the interface.

TaskScheduler scheduler =
        TaskScheduler.builder(() -> {})
                .interval(5, TimeUnit.SECONDS)
                .initialDelay(15)
                .build();

TemporalField<LocalDate> field =
        TemporalField.builder(LocalDate.class, "dd.MM.yyyy")
                .columns(12)
                .border(createTitledBorder("Date"))
                .build();

6.2. Accessors

Immutable fields and attributes are accessed using methods named after the field, without a get/is prefix.

EventObserver<String> observer = event.observer();

LocalEntityConnection connection = connectionProvider.connection();

boolean modified = entity.modified();

Entity.Key primaryKey = entity.primaryKey();

A get/is prefix implies that the field is mutable and that a corresponding setter method with a set prefix exists.

boolean optimisticLocking = connection.isOptimisticLocking();

connection.setOptimisticLocking(false);

List<Integer> selectedIndexes = selectionModel.getSelectedIndexes();

selectionModel.setSelectedIndexes(Arrays.asList(0, 1, 2));

6.3. Exceptions

There are a few exceptions to these rules, such as a get prefix on an accessor for a functionally immutable field, but these exceptions are usually to keep the style of a class being extended, such as Swing components and should be few and far between.

7. Modules

7.1. Common

Common classes used throughout the framework.

codion-common-core

Dependency graph
dependency graph

codion-common-db

JDBC related classes.

Dependency graph
dependency graph

codion-common-model

Common model classes.

Dependency graph
dependency graph

codion-common-i18n

Dependency graph
dependency graph

codion-common-rmi

RMI related classes.

Dependency graph
dependency graph

7.2. DBMS

Database specific implementation classes.

codion-dbms-db2database

Dependency graph
dependency graph

codion-dbms-derby

Dependency graph
dependency graph

codion-dbms-h2database

Dependency graph
dependency graph

codion-dbms-hsqldb

Dependency graph
dependency graph

codion-dbms-mariadb

Dependency graph
dependency graph

codion-dbms-mysql

Dependency graph
dependency graph

codion-dbms-oracle

Dependency graph
dependency graph

codion-dbms-postgresql

Dependency graph
dependency graph

codion-dbms-sqlite

Dependency graph
dependency graph

codion-dbms-sqlserver

Dependency graph
dependency graph

7.3. Framework

The framework itself.

codion-framework-domain

Domain model related classes.

Dependency graph
dependency graph

codion-framework-domain-test

Domain model unit test related classes.

Dependency graph
dependency graph

codion-framework-db-core

Core database connection related classes.

Dependency graph
dependency graph

codion-framework-db-local

Local JDBC connection related classes.

Dependency graph
dependency graph

codion-framework-db-rmi

RMI connection related classes.

Dependency graph
dependency graph

codion-framework-db-http

HTTP connection related classes.

Dependency graph
dependency graph

codion-framework-i18n

Internationalization strings.

Dependency graph
dependency graph

codion-framework-json-domain

Dependency graph
dependency graph

codion-framework-json-db

Dependency graph
dependency graph

codion-framework-model

Common framework model classes.

Dependency graph
dependency graph

codion-framework-model-test

General application model unit test related classes.

Dependency graph
dependency graph

codion-framework-server

Framework server classes.

Dependency graph
dependency graph

codion-framework-servlet

HTTP servlet server classes.

Dependency graph
dependency graph

7.4. Swing

Swing client implementation.

codion-swing-common-model

Common Swing model classes.

Dependency graph
dependency graph

codion-swing-common-ui

Common Swing UI classes.

Dependency graph
dependency graph

codion-swing-common-model-tools

Dependency graph
dependency graph

codion-swing-common-ui-tools

Dependency graph
dependency graph

codion-swing-framework-model

Dependency graph
dependency graph

codion-swing-framework-ui

Dependency graph
dependency graph

codion-swing-framework-ui-test

Dependency graph
dependency graph

codion-swing-framework-model-tools

Dependency graph
dependency graph

codion-swing-framework-ui-tools

Dependency graph
dependency graph

codion-swing-framework-server-monitor

Dependency graph
dependency graph

7.5. Plugins

7.5.1. Logging

codion-plugin-jul-proxy
Dependency graph
dependency graph
codion-plugin-log4j-proxy
Dependency graph
dependency graph
codion-plugin-logback-proxy
Dependency graph
dependency graph

7.5.2. Connection pools

codion-plugin-hikari-pool
Dependency graph
dependency graph
codion-plugin-tomcat-pool
Dependency graph
dependency graph

7.5.3. Reporting

codion-plugin-jasperreports
Dependency graph
dependency graph

7.5.4. Other

codion-plugin-imagepanel
Dependency graph
dependency graph

8. Utilities

8.1. IntelliJ IDEA

8.1.1. Live templates

Here are a few live templates for IntelliJ, reducing the typing required when defining a domain model.

Add this file to the templates directory in the IntelliJ IDEA configuration directory.

View template file
<templateSet group="codion">
  <template name="cod" value="Column&lt;Double&gt; $ATTRIBUTE_NAME$ = TYPE.doubleColumn(&quot;$COLUMN_NAME$&quot;);$END$" description="Column&lt;Double&gt;" toReformat="false" toShortenFQNames="true">
    <variable name="COLUMN_NAME" expression="" defaultValue="" alwaysStopAt="true" />
    <variable name="ATTRIBUTE_NAME" expression="groovyScript(&quot;_1.toUpperCase()&quot;, COLUMN_NAME)" defaultValue="" alwaysStopAt="true" />
    <context>
      <option name="JAVA_DECLARATION" value="true" />
    </context>
  </template>
  <template name="coi" value="Column&lt;Integer&gt; $ATTRIBUTE_NAME$ = TYPE.integerColumn(&quot;$COLUMN_NAME$&quot;);$END$" description="Column&lt;Integer&gt;" toReformat="false" toShortenFQNames="true">
    <variable name="COLUMN_NAME" expression="" defaultValue="" alwaysStopAt="true" />
    <variable name="ATTRIBUTE_NAME" expression="groovyScript(&quot;_1.toUpperCase()&quot;, COLUMN_NAME)" defaultValue="" alwaysStopAt="true" />
    <context>
      <option name="JAVA_DECLARATION" value="true" />
    </context>
  </template>
  <template name="col" value="Column&lt;Long&gt; $ATTRIBUTE_NAME$ = TYPE.longColumn(&quot;$COLUMN_NAME$&quot;);$END$" description="Column&lt;Long&gt;" toReformat="false" toShortenFQNames="true">
    <variable name="COLUMN_NAME" expression="" defaultValue="" alwaysStopAt="true" />
    <variable name="ATTRIBUTE_NAME" expression="groovyScript(&quot;_1.toUpperCase()&quot;, COLUMN_NAME)" defaultValue="" alwaysStopAt="true" />
    <context>
      <option name="JAVA_DECLARATION" value="true" />
    </context>
  </template>
  <template name="cos" value="Column&lt;String&gt; $ATTRIBUTE_NAME$ = TYPE.stringColumn(&quot;$COLUMN_NAME$&quot;);$END$" description="Column&lt;String&gt;" toReformat="false" toShortenFQNames="true">
    <variable name="COLUMN_NAME" expression="" defaultValue="" alwaysStopAt="true" />
    <variable name="ATTRIBUTE_NAME" expression="groovyScript(&quot;_1.toUpperCase()&quot;, COLUMN_NAME)" defaultValue="" alwaysStopAt="true" />
    <context>
      <option name="JAVA_DECLARATION" value="true" />
    </context>
  </template>
  <template name="fk" value="ForeignKey $ATTRIBUTE_NAME$ = TYPE.foreignKey(&quot;$FK_NAME$&quot;, $END$);" description="ForeignKey" toReformat="false" toShortenFQNames="true">
    <variable name="FK_NAME" expression="" defaultValue="" alwaysStopAt="true" />
    <variable name="ATTRIBUTE_NAME" expression="groovyScript(&quot;_1.toUpperCase()&quot;, FK_NAME)" defaultValue="" alwaysStopAt="true" />
    <context>
      <option name="JAVA_DECLARATION" value="true" />
    </context>
  </template>
  <template name="cold" value="Column&lt;LocalDate&gt; $ATTRIBUTE_NAME$ = TYPE.localDateColumn(&quot;$COLUMN_NAME$&quot;);$END$" description="Column&lt;LocalDate&gt;" toReformat="false" toShortenFQNames="true">
    <variable name="COLUMN_NAME" expression="" defaultValue="" alwaysStopAt="true" />
    <variable name="ATTRIBUTE_NAME" expression="groovyScript(&quot;_1.toUpperCase()&quot;, COLUMN_NAME)" defaultValue="" alwaysStopAt="true" />
    <context>
      <option name="JAVA_DECLARATION" value="true" />
    </context>
  </template>
  <template name="coldt" value="Column&lt;LocalDateTime&gt; $ATTRIBUTE_NAME$ = TYPE.localDateTimeColumn(&quot;$COLUMN_NAME$&quot;);$END$" description="Column&lt;LocalDateTime&gt;" toReformat="false" toShortenFQNames="true">
    <variable name="COLUMN_NAME" expression="" defaultValue="" alwaysStopAt="true" />
    <variable name="ATTRIBUTE_NAME" expression="groovyScript(&quot;_1.toUpperCase()&quot;, COLUMN_NAME)" defaultValue="" alwaysStopAt="true" />
    <context>
      <option name="JAVA_DECLARATION" value="true" />
    </context>
  </template>
  <template name="et" value="EntityType TYPE = DOMAIN.entityType(&quot;$TABLE_NAME$&quot;);$END$" description="EntityType" toReformat="false" toShortenFQNames="true">
    <variable name="TABLE_NAME" expression="" defaultValue="" alwaysStopAt="true" />
    <context>
      <option name="JAVA_DECLARATION" value="true" />
    </context>
  </template>
  <template name="cob" value="Column&lt;Boolean&gt; $ATTRIBUTE_NAME$ = TYPE.booleanColumn(&quot;$COLUMN_NAME$&quot;);$END$" description="Column&lt;Boolean&gt;" toReformat="false" toShortenFQNames="true">
    <variable name="COLUMN_NAME" expression="" defaultValue="" alwaysStopAt="true" />
    <variable name="ATTRIBUTE_NAME" expression="groovyScript(&quot;_1.toUpperCase()&quot;, COLUMN_NAME)" defaultValue="" alwaysStopAt="true" />
    <context>
      <option name="JAVA_DECLARATION" value="true" />
    </context>
  </template>
  <template name="cosh" value="Column&lt;Short&gt; $ATTRIBUTE_NAME$ = TYPE.shortColumn(&quot;$COLUMN_NAME$&quot;);$END$" description="Column&lt;Short&gt;" toReformat="false" toShortenFQNames="true">
    <variable name="COLUMN_NAME" expression="" defaultValue="" alwaysStopAt="true" />
    <variable name="ATTRIBUTE_NAME" expression="groovyScript(&quot;_1.toUpperCase()&quot;, COLUMN_NAME)" defaultValue="" alwaysStopAt="true" />
    <context>
      <option name="JAVA_DECLARATION" value="true" />
    </context>
  </template>
  <template name="coc" value="Column&lt;Character&gt; $ATTRIBUTE_NAME$ = TYPE.characterColumn(&quot;$COLUMN_NAME$&quot;);$END$" description="Column&lt;Character&gt;" toReformat="false" toShortenFQNames="true">
    <variable name="COLUMN_NAME" expression="" defaultValue="" alwaysStopAt="true" />
    <variable name="ATTRIBUTE_NAME" expression="groovyScript(&quot;_1.toUpperCase()&quot;, COLUMN_NAME)" defaultValue="" alwaysStopAt="true" />
    <context>
      <option name="JAVA_DECLARATION" value="true" />
    </context>
  </template>
  <template name="coodt" value="Column&lt;OffsetDateTime&gt; $ATTRIBUTE_NAME$ = TYPE.offsetDateTimeColumn(&quot;$COLUMN_NAME$&quot;);$END$" description="Column&lt;OffsetDateTime&gt;" toReformat="false" toShortenFQNames="true">
    <variable name="COLUMN_NAME" expression="" defaultValue="" alwaysStopAt="true" />
    <variable name="ATTRIBUTE_NAME" expression="groovyScript(&quot;_1.toUpperCase()&quot;, COLUMN_NAME)" defaultValue="" alwaysStopAt="true" />
    <context>
      <option name="JAVA_DECLARATION" value="true" />
    </context>
  </template>
  <template name="coby" value="Column&lt;byte[]&gt; $ATTRIBUTE_NAME$ = TYPE.byteArrayColumn(&quot;$COLUMN_NAME$&quot;);$END$" description="Column&lt;byte[]&gt;" toReformat="false" toShortenFQNames="true">
    <variable name="COLUMN_NAME" expression="" defaultValue="" alwaysStopAt="true" />
    <variable name="ATTRIBUTE_NAME" expression="groovyScript(&quot;_1.toUpperCase()&quot;, COLUMN_NAME)" defaultValue="" alwaysStopAt="true" />
    <context>
      <option name="JAVA_DECLARATION" value="true" />
    </context>
  </template>
</templateSet>
Available templates

Name

Template

et

EntityType TYPE = DOMAIN.entityType("table_name");

fk

ForeignKey FK_KEY = TYPE.foreignKey("fk_key");

cosh

Column<Short> COLUMN = TYPE.shortColumn("column");

coi

Column<Integer> COLUMN = TYPE.integerColumn("column");

col

Column<Long> COLUMN = TYPE.longColumn("column");

cod

Column<Double> COLUMN = TYPE.doubleColumn("column");

cos

Column<String> COLUMN = TYPE.stringColumn("column");

cold

Column<LocalDate> COLUMN = TYPE.localDateColumn("column");

coldt

Column<LocalDateTime> COLUMN = TYPE.localDateTimeColumn("column");

coodt

Column<OffsetDateTime> COLUMN = TYPE.offsetDateTimeColumn("column");

cob

Column<Boolean> COLUMN = TYPE.booleanColumn("column");

coc

Column<Character> COLUMN = TYPE.characterColumn("column");

coby

Column<byte[]> COLUMN = TYPE.byteArrayColumn("column");