EnkiDevelopment
This page explains the mechanics for how to get started working on Enki development.
Contents |
Get Source Code
You can pull the latest Enki code from the Eigenbase Perforce server. If you're new to Perforce, you might want to read the official Perforce Quick Start. If you don't already have a p4 client program, download the appropriate binary from Perforce (you only need the free-as-in-beer client, not the server).
There are a number of ways to configure Perforce depending on the platform (on Windows through the GUI, on Unix through environment variables or a .p4env file). The essential information you need to provide is:
- P4PORT=perforce.eigenbase.org:1666
- P4USER=your-user-name
- P4CLIENT=your-user-name.your-hostname
You can use "guest" for the user name if you don't have commit access to Eigenbase yet.
Once you've got Perforce set up, run p4 client (or edit your default clientspec from P4WIN). Map your view to match this example:
View:
//open/enki/... //YOURCLIENT/enki/...
While editing your client, you should also set the LineEnd attribute to share if you are developing on Windows or using Samba. This prevents DOS CRLF's from getting checked in.
Finally, run p4 sync to get all the source files and thirdparty distributions into your client workspace. This may take a while because some of the thirdparty distributions are large.
We'll refer to the workspace directory created by this as enki.
If you want to skip Perforce setup and instead start from a fairly recent distribution tarball, download it here (and the thirdparty libraries from here).
Configure Workspace
The next step after pulling the code is to do some one-time setup for your workspace.
Unpack the thirdparty distributions:
cd enki/thirdparty make all
Next in the enki directory, create a new file customBuild.properties as follows:
enki.impl.default=netbeans
This will get you started testing against the Netbeans MDR implementation, using hsqldb for persistence. Below we'll explain how to switch to the Hibernate implementation.
Build and Test
You must have Apache ant installed, and in particular you should be using the same one as the rest of Eigenbase. The first thing to try is a full build followed by running all tests applicable to Netbeans:
ant test
Unit test results get written to enki/test/results.
After that, if you make some code changes and want to just build them without running tests:
ant compile
(Or just run ant since compile is the default target.)
Finally, if you make changes to the Sample Metamodel or to the way that Enki generates code for metamodels, you can rebuild the Sample Metamodel without running tests:
ant createSampleRepository
If you care about the Sample Plugin Metamodel, that can be rebuilt (usually after a rebuild of the Sample Metamodel) as well:
ant createSamplePluginRepository
java.util.logging trace output is written to enki/trace/EnkiTrace.log, with verbosity controlled by enki/trace/EnkiTrace.properties.
You can run a single test class from the command line as follows:
jvs@bagheera:~/open/enki$ junitSingle JmiTest
Buildfile: build.xml
test-only:
[echo] **********************************************
[echo] Testing hibernate implementation
[echo] **********************************************
[junit] Running org.eigenbase.enki.test.JmiTest
[junit] Tests run: 15, Failures: 0, Errors: 0, Time elapsed: 5.585 sec
test-plugin-only:
BUILD SUCCESSFUL
Total time: 8 seconds
The enki/junitSingle script uses the ant pattern **/JmiTest.class to find the class regardless of which package it lives in.
Sample Metamodel
Enki comes with a sample metamodel on which its unit tests are based. It's named "EEM" for Enki Extension Metamodel, and is defined in enki/test/sample/catalog/xmi/Sample.uml.
You can edit it using ArgoUML. Here's one of the diagrams (the actual model is much bigger for covering lots of corner cases):
For the first build after saving the new model, you'll need to run ant createSampleRepository instead of a normal compile so that Enki will regenerate all of the code and persistence derived from the UML. This is also a quick way to get back to a clean state after dirtying the sample repository during testing and debugging.
Switch to Hibernate
To switch to the Hibernate+MySQL implementation for testing, edit customBuild.properties again:
enki.impl.default=hibernate
For the default settings, you'll need a MySQL instance running on your same machine, with MySQL user root and no password, and with the InnoDB storage engine available. Tests will drop+create a MySQL database named ENKI. Run ant test again to create the MySQL repository and run all the Hibernate tests; this time it will take longer.
You can also use the Hibernate implementation against HSQLDB by editing customBuild.properties to look like this:
enki.impl.default=hibernate-hsqldb
Checkin Guidelines
If you have Perforce submit access, or are sending patches to the project, here are some guidelines to follow for a successful submission:
- follow the Eigenbase coding conventions; if you use Emacs, set it up to load Eigenbase EmacsCustomizations
- run all tests for both Netbeans, Hibernate and Transient and resolve any failures (ant test-all-impls can run through all of them automatically)
- ant test will also verify that Javadoc can be built with zero errors/warnings; be sure to fix any problems it identifies (you can also run ant checkJavadoc to verify this in isolation, and ant javadoc to actually generate the Javadoc without deleting it)
- add new unit test coverage for all changes, including new features and bugfixes
If your checkin causes any problems the next time an Enki release is integrated into a dependent project such as Farrago, you'll be asked to help resolve that.
There are also some optional tests (ant test-umlm2) which aren't currently integrated into the main unit tests; if these break, they'll need to be fixed once someone notices.
Release Build
The official release process for Enki as a standalone subproject of Eigenbase has not yet been defined, but there have already been internal releases into other projects such Farrago and argouml-enki.
Building a release requires you to first create a file enki/dist/EnkiRelease.properties:
package.name=eigenbase-enki product.name=Eigenbase Metadata Repository product.version.major=0 product.version.minor=1 product.version.point=0
For now we use version "0.1.0" until official releases start.
Next, make sure you have no files checked out from Perforce, and have sync'd to the latest code to be released.
In the enki directory, run the distBuild.sh script. It will query Perforce to figure out the revision number for the latest change and include that metadata in the released package (as a file named LAST_CHANGE). Don't use the ant dist target directly unless you want to bypass the Perforce query, e.g. to build a release from something other than the latest code. In that case, you'll need to create the enki/dist/LAST_CHANGE file yourself.
A successful distribution build will produce the following in the enki/dist directory:
- eigenbase-enki-0.1.0-doc.jar: the generated Javadoc
- eigenbase-enki-0.1.0-findbugs.jar: the findbugs plugin for detecting errors in applications built on Enki
- eigenbase-enki-0.1.0.jar: the compiled classes for Enki
- eigenbase-enki-0.1.0-libs.tar.gz: redistribution of thirdparty libraries required by Enki
- eigenbase-enki-0.1.0-src.jar: source code for Enki
- LAST_CHANGE: metadata about the build version, which is also included in most of the files above (along with a copy of the LGPL) to make them independently redistributable
- eigenbase-enki-0.1.0.tar.gz: a tarball containing all of the files above
Eclipse Environment
Enki (as of change 12238) has an Ant target to generate a basic Eclipse project.
After building and running unit tests via Ant (or at least executing ant createSampleRepository createSamplePluginRepository), you can create an eclipse project by running ant createEclipseProject.
To configure a non-plugin JUnit test to run with Eclipse, use the JUnit 4 Test Runner and specify the following JVM arguments, substituting your project's name for ENKI_PROJECT_NAME:
-Denki.home=${workspace_loc:ENKI_PROJECT_NAME}
-Denki.test.extent=SampleRepository
For plug-in tests (see #Writing Unit Tests), the classpath for JUnit tests must include both the sample.jar and sample-plugin.jar JAR files. The JVM arguments for plugin tests are as follows, again replacing your project's name for ENKI_PROJECT_NAME:
-Denki.home=${workspace_loc:ENKI_PROJECT_NAME}
-Denki.test.extent=SamplePluginRepository
-Denki.test.storageProps=${workspace_loc:ENKI_PROJECT_NAME}/test/TestPluginStorage.properties
Note that if you make changes to the sample metamodel, you'll need to rebuild them with Ant and refresh the sample.jar and/or sample-plugin.jar JAR files in Eclipse.
Eclipse 3.3 sometimes encounters NullPointerExceptions in its compiler, particularly if you are examining files in Eclipse while building via Ant. Once in that state, the only solution seems to be to disable automatic building, clean the project, and restart. A workaround is to always disable automatic building and use the Ant scripts exclusively for compilation.
Writing Unit Tests
Package
New unit tests should be placed in the org.eigenbase.enki.test package. Several sub-packages exists there which contain specific subsets of tests:
| Package | Description |
|---|---|
org.eigenbase.enki.test.performance
|
Performance related tests. These tests are not normally executed as part of the test or test-all-impls Ant targets.
|
org.eigenbase.enki.test.plugin
|
Tests that rely on the sample metamodel plus the sample plug-in extension. These tests must use the reflective JMI interfaces exclusively as the plug-in's interfaces are not available at build time. Tests in this package are automatically run against a separate repository containing the plug-in's metamodel. |
org.eigenbase.enki.test.hibernate
|
Tests that exercise functionality of the Enki/Hibernate provider. Tests in this package must use the annotation @RunWith(HibernateOnlyTestRunner.class) to avoid being executed with non-Enki/Hibernate repositories.
|
org.eigenbase.enki.test.events
|
The events package contains infrastructure for testing the MDR Events API and includes no tests. |
Base Class
Tests that extend org.eigenbase.enki.test.ModelTestBase automatically load the sample or sample plug-in repository. The repository loaded depends on whether the base class loads the default test storage properties (e.g., test/TestStorage.properties) or if configured to use an alternate location (e.g., test/TestPluginStorage.properties). Both properties files are copied and have variables resolved by the Ant script from templates under test/config.
ModelTestBase also automatically deletes all objects from the repository before any of the concrete test class's setup or test methods are invoked. The base class also provides convenience methods to manage session and transactions, delete all repository objecgts, reload the extent, or shutdown and restart the repository. See the javadoc for details.
The test base class org.eigenbase.enki.SampleModelTestBase extends ModelTestBase to provide convenience methods to obtain package interfaces for the sample metamodel's packages.
Each test class configures and starts the repository. A session is started by ModelTestBase<code> before any sub-class setup or test methods are invoked. You may end the session (assuming all transactions are also ended), but must start a new session before exiting your method.
All tests must be marked with JUnit 4 annotations: <code>@Test denotes a test. @Ignore causes a test to be skipped.
The test class should be marked with @RunWith(LoggingTestRunner.class) to provide automatic logging of the start and end of each test, which makes interpreting the log file much simpler.
You may use the @BeforeClass, @Before, @After, and @AfterClass annotations for per-class and per-test setup and teardown.
Execution
The Ant build script assumes that all classes in under org.eigenbase.enki.test whose names end with Test are JUnit 4 unit tests.
Tests in the org.eigenbase.enki.test.plugin are executed against a separate plug-in repository.
The script junitSingle can be used to execute a single unit test from the command line.
Ant Target: test
The Ant target test makes a clean build of the sample and plug-in repositories and then executes all non-plug-in, non-performance unit tests with the sample.jar JAR file on the classpath and the following JVM arguments:
-ea
-esa
-Denki.home={enki directory}
-Denki.test.extent=SampleRepository
-Djava.util.logging.config.file={enki directory}/trace/EnkiTrace.properties
It then executes the plug-in unit tests with the addition of the sample-plugin.jar JAR file on the classpath, changes the test extent JVM argument and adds an extra JVM argument:
-Denki.test.extent=SamplePluginRepository
-Denki.test.storageProps={enki directory}/test/TestPluginStorage.properties
Finally it verifies that no warnings or errors are emitted as part of JavaDoc generation.
Ant Target: test-all-impls
The Ant target test-all-impls forks an instance of Ant for each standard repository configuration (currently netbeans, hibernate, hibernate-hsqldb, and transient) and runs the same set of tests as the test target. It then verifies the JavaDoc once after all the tests have passed.
Tracing Hibernate and MySQL
Hibernate SQL statements may be dumped to the standard output by enabling following property in the appropriate storage properites file:
hibernate.show_sql=true
Alternatively, you can have the SQL dumped to the trace file by adding this line to trace/EnkiTrace.properties:
org.hibernate.SQL.level=FINE
In both cases, you're seeing the SQL statements the Hibernate generates without regard to the second level cache, if any.
Enki's Ant scripts contain several convenience methods to control a local MySQL installation. By default Enki assumes MySQL is installed at the location referenced by the environment variable MYSQL_HOME. That directory must contain a sub-directory called bin which contains the mysqld executable. You may alternatively specify MySQL's installation directory via the mysql.inst.dir Ant property in customBuild.properties.
The following targets may be used to control MySQL from Enki's build directory:
- start-mysql-server - starts MySQL
- stop-mysql-server - stops MySQL
- restart-mysql-server - equivalent to ant stop-mysql-server start-mysql-server
- start-mysql-server-with-logging - starts MySQL with query logging enabled
- restart-mysql-server-with-logging - equivalent to ant stop-mysql-server start-mysql-server-with-logging
MySQL's query logging has the advantage of displaying the values of parameterized SQL statements whereas Hibernate's logging only shows the parameterized SQL.
More Resources
- EnkiDocs: top-level document index for the Enki project
- ant etags will generate a TAGS file usable by Emacs
