This contributors' guide is for:
programmers who want to just use Apache Isis to build applications, and want help setting up their development environment or to build their code from the command line (eg to execute within a continuous integration server such as Jenkins)
programmers who want to contribute back patches (bug fixes, new features) either to the codebase or the framework’s documentation
committers of Apache Isis itself who want guidance on release process, publishing documents and other related procedures.
Apache Isis documentation is broken out into a number of user, reference and "supporting procedures" guides.
The user guides available are:
The reference guides are:
The "supporting procedures" guides are:
Contributors' Guide (this guide)
Committers' Guide (release procedures and related practices)
The vast majority of Java developers use an IDE to assist with developing their code, and we highly recommend that you do like wise as you develop your Apache Isis applications using an IDE. Apache Isis is built with Maven, and all modern IDEs can import Maven projects.
This chapter shows how to setup and use two of the most popular IDEs, IntelliJ IDEA and Eclipse.
This material does not constitute an endorsement; JetBrains is not affiliated to Apache Software Foundation in any way. |
This section describes how to install and setup JetBrains' IntelliJ IDEA, then how to import an application into IntelliJ and run it.
This section covers installation and setup. These notes relates to IntelliJ Community Edition 14.1.x, with screenshots taken for Windows.
Download latest version of IntelliJ Community Edition, and install:
Start the wizard, click through the welcome page:
Choose the location to install the IDE:
Adjust any installation options as you prefer:
and the start menu:
and finish up the wizard:
Later on we’ll specify the Apache Isis/ASF code style settings, so for now select I do not want to import settings
:
Finally, if you are young and trendy, set the UI theme to Darcula:
In IntelliJ a project can contain multiple modules; these need not be physically located together. (If you are previously an Eclipse user, you can think of it as similar to an Eclipse workspace).
Start off by creating a new project:
We want to create a new Java project:
We therefore need to specify the JDK.
at the time of writing Apache Isis supports only Java 7; Java 8 is scheduled for support in Apache Isis v1.9.0 |
Specify the directory containing the JDK:
Finally allow IntelliJ to create the directory for the new project:
Next we need to configure IntelliJ with ASF/Apache Isis' standard templates and coding conventions. These are bundled as the settings.jar
JAR file download from the Apache Isis website).
Import using: File > Import Settings
, and specify the directory that you have downloaded the file to:
Select all the (two) categories of settings available in the JAR file:
And then restart:
There are also some other settings that influence the compiler. We highly recommend you set these.
On the Compiler Settings page, ensure that build automatically
is enabled (and optionally compile independent modules in parallel
):
On the Annotation Processors page, enable and adjust for the 'default' setting:
This setting enables the generation of the Q*
classes for DataNucleus type-safe queries, as well as being required
for frameworks such as Project Lombok.
IntelliJ may also have inferred these settings for specific projects/modules when importing; review the list on the left to see if the default is overridden and fix/delete as required. |
There are also some other settings for Maven that we recommend you adjust (though these are less critical):
First, specify an up-to-date Maven installation, using File > Settings
(or IntelliJ > Preferences
if on MacOS):
Still on the Maven settings page, configure as follows:
These settings are optional but also recommended.
On the auto import page, check the optimize imports on the fly
and add unambiguous imports on the fly
Let’s load in some actual code! We do this by importing the Maven modules.
First up, open up the Maven tool window (View > Tool Windows > Maven Projects
). You can then use the 'plus' button to add Maven modules. In the screenshot you can see we’ve loaded in Apache Isis core; the modules are listed in the Maven Projects window and corresponding (IntelliJ) modules are shown in the Projects window:
We can then import another module (from some other directory). For example, here we are importing the Isis Addons' todoapp example:
You should then see the new Maven module loaded in the Projects window and also the Maven Projects window:
If any dependencies are already loaded in the project, then IntelliJ will automatically update the CLASSPATH to resolve to locally held modules (rather from .m2/repository
folder). So, for example (assuming that the <version>
is correct, of course), the Isis todoapp will have local dependencies on the Apache Isis core.
You can press F4 (or use File > Project Structure
) to see the resolved classpath for any of the modules loaded into the project.
If you want to focus on one set of code (eg the Isis todoapp but not Apache Isis core) then you could remove the module; but better is to ignore those modules. This will remove from the the Projects window but keep them available in the Maven Projects window for when you next want to work on them:
Confirm that it’s ok to ignore these modules:
All being well you should see that the Projects window now only contains the code you are working on. Its classpath dependencies will be adjusted (eg to resolve to Apache Isis core from .m2/repository
):
Let’s see how to run both the app and the tests.
Once you’ve imported your Isis application, we should run it. We do this by creating a Run configuration, using Run > Edit Configurations
.
Set up the details as follows:
We specify the Main class
to be org.apache.isis.WebServer
; this is a wrapper around Jetty. It’s possible to pass program arguments to this (eg to automatically install fixtures), but for now leave this blank.
Also note that Use classpath of module
is the webapp module for your app, and that the working directory
is $MODULE_DIR$
.
Next, and most importantly, configure the DataNucleus enhancer to run for your dom
goal. This can be done by defining a Maven goal to run before the app:
The -o
flag in the goal means run off-line; this will run faster.
if you forget to set up the enhancer goal, or don’t run it on the correct (dom) module, then you will get all sorts of errors when you startup. These usually manifest themselves as class cast exception in DataNucleus. |
You should now be able to run the app using Run > Run Configuration
. The same configuration can also be used to debug the app if you so need.
The easiest way to run the unit tests is just to right click on the dom
module in the Project Window, and choose run unit tests. Hopefully your tests will pass (!).
As a side-effect, this will create a run configuration, very similar to the one we manually created for the main app:
Thereafter, you should run units by selecting this configuration (if you use the right click approach you’ll end up with lots of run configurations, all similar).
Integration tests can be run in the same way as unit tests, however the dom
module must also have been enhanced.
One approach is to initially run the tests use the right click on the integtests
module; the tests will fail because the code won’t have been enhanced, but we can then go and update the run configuration to run the datanucleus enhancer goal (same as when running the application):
You can download 1-page PDFs cheat sheets for IntelliJ’s keyboard shortcuts: * for Windows * for MacOS
Probably the most important shortcut on them is for Find Action
:
- ctrl-shift-A
on Windows
- cmd-shift-A
on MacOS.
This will let you search for any action just by typing its name.
The Tool Windows are the views around the editor (to left, bottom and right). It’s possible to move these around to your preferred locations.
Use alt-1
through alt-9
(or cmd-1
through alt-9
) to select the tool windows
Press it twice and the tool window will hide itself; so can use to toggle
If in the Project Window (say) and hit enter on a file, then it will be shown in the editor, but (conveniently) the focus remains in the tool window. To switch to the editor, just press Esc
.
If in the Terminal Window, you’ll need to press Shift-Esc
.
If on the editor and want to locate the file in (say) the Project Window, use alt-F1
.
To change the size of any tool window, use ctrl-shift-arrow
Using these shortcuts you can easily toggle between the tool windows and the editor, without using the mouse. Peachy!
For all of the following, you don’t need to type every letter, typing "ab" will actually search for ".a.*b.".
to open classes or files or methods that you know the name of:
ctrl-N
to open class
ctrl-shift-N
to open a file
(bit fiddly this) ctrl-shift-alt-N
to search for any symbol.
open up dialog of recent files: ctrl-E
search for any file: shift-shift
Navigating around:
* find callers of a method (the call hierarchy): ctrl-alt-H
* find subclasses or overrides: ctrl-alt-B
* find superclasses/interface/declaration: ctrl-B
Viewing the structure (ie outline) of a class
* ctrl-F12
will pop-up a dialog showing all members
** hit ctrl-F12
again to also see inherited members
Extend selection using ctrl-W
and contract it down again using ctrl-shift-W
to duplicate a line, it’s ctrl-D
if you have some text selected (or even some lines), it’ll actually duplicate the entire selection
to delete a line, it’s ctrl-X
to move a line up or down: shift-alt-up
and shift-alt-down
if you have selected several lines, it’ll move them all togethe
ctrl-shift-J
can be handy for joining lines together
just hit enter to split them apart (even in string quotes; IntelliJ will "do the right thing")
Massively useful is the "Intentions" popup; IntelliJ tries to guess what you might want to do. You can activate this using`alt-enter`, whenever you see a lightbulb/tooltip in the margin of the current line.
Code completion usually happens whenever you type '.'. You can also use ctrl-space
to bring these up.
In certain circumstances (eg in methods0) you can also type ctrl-shift-space
to get a smart list of methods etc that you might want to call. Can be useful.
Last, when invoking a method, use ctrl-P
to see the parameter types.
Loads of good stuff on the Refactor
menu; most used are:
Rename (shift-F6
)
Extract
method: ctrl-alt-M
variable: ctrl-alt-V
Inline method/variable: ctrl-alt-N
Change signature
If you can’t remember all those shortcuts, just use ctrl-shift-alt-T
(might want to rebind that to something else!) and get a context-sensitive list of refactorings available for the currently selected object
You might want to set up some additional plugins. You can do this using File > Settings > Plugins
(or equivalently File > Other Settings > Configure Plugins
).
Recommended are:
Maven Helper plugin
AsciiDoctor plugin
Useful if you are doing any authoring of documents.
Some others you might like to explore are:
This plugin provides a couple of great features. One is better visualization of dependency trees (similar to Eclipse).
If you open a pom.xml
file, you’ll see an additional "Dependencies" tab:
Clicking on this gives a graphical tree representation of the dependencies, similar to that obtained by mvn dependency:tree
, but filterable.
The plugin also provides the ability to easily run a Maven goal on a project:
This menu can also be bound to a keystroke so that it is available as a pop-up:
When a Maven module is imported, IntelliJ generates its own project files (suffix .ipr
), and the application is actually built from that.
Occasionally these don’t keep in sync (even if auto-import of Maven modules has been enabled).
To fix the issue, try: * reimport module * rebuild selected modules/entire project * remove and then re-add the project * restart, invalidating caches * hit StackOverflow (!)
One thing worth knowing; IntelliJ actively scans the filesystem all the time. It’s therefore (almost always) fine to build the app from the Maven command line; IntelliJ will detect the changes and keep in sync. If you want to force that, use File > Synchronize
, ctrl-alt-Y
.
If you hit an error of "duplicate classes":
then make sure you have correctly configured the annotation processor settings. Pay attention in particular to the "Production sources directory" and "Test sources directory", that these are set up correctly.
When running integration tests from within IntelliJ, make sure that the search for tests
radio button is set to In single module
:
If this radio button is set to one of the other options then you may obtain class loading issues; these result from IntelliJ attempting to run unit tests of the dom
project that depend on test classes in that module, but using the classpath of the integtests
module whereby the dom
test-classes (test-jar
artifact) are not exposed on the Maven classpath.
In this section are a couple of options that will reduce the length of the change code/build/deploy/review feedback loop.
DCEVM enhances the JVM with true hot-swap adding/removing of methods as well as more reliable hot swapping of the implementation of existing methods.
In the context of Apache Isis, this is very useful for contributed actions and mixins and also view models; you should then be able to write these actions and have them be picked up without restarting the application.
Changing persisting domain entities is more problematic, for two reasons: the JDO/DataNucleus enhancer needs to run on domain entities, and also at runtime JDO/DataNucleus would need to rebuild its own metamodel. You may find that adding actions will work, but adding new properties or collections is much less likely to.
To set up DCEVM, download the appropriate JAR from the github page, and run the installer. For example:
java -jar DCEVM-light-8u51-installer.jar
Be sure to run with appropriate privileges to be able to write to the installation directories of the JDK. If running
on Windows, that means running as |
After a few seconds this will display a dialog listing all installations of JDK that have been found:
Select the corresponding installation, and select Replace by DCEVM
.
In IntelliJ, register the JDK in File > Project Structure
dialog:
Finally, in the run configuration, select the patched JDK:
See the repo for the (non-ASF) Isis JRebel plugin. With some modification, this should work for IntelliJ too.
Note that JRebel is a commercial product, requiring a license. At the time of writing there is also currently a non-commercial free license (though note this comes with some usage conditions).
This material does not constitute an endorsement; Eclipse foundation is not affiliated to Apache Software Foundation in any way. |
If you are an Eclipse user, then we recommend you download the "Eclipse JEE package" configuration.
When running an Apache Isis application, it’s necessary to setup the development environment so that the Java bytecode can be enhanced by the DataNucleus enhancer. If working in Eclipse, then JDO enhancement is most easily done by installing the DataNucleus' Eclipse plugin. This hooks the bytecode enhancement of your domain objects into Eclipse’s normal incremental compilation.
This plugin needs to be configured for each of your domain modules (usually just one in any given app). The steps are therefore:
import the project into Eclipse
configure the DataNucleus enhancer
run the app from the .launch
file
The following screencast shows how to import an Apache Isis maven-based application into Eclipse and configure to use with the JDO Objectstore
Use File > Import, then Maven > Existing Maven Projects.
Make sure you are in the 'Java' Perspective, not the 'Java EE' Perspective. |
In Eclipse, for the domain object model project, first add DataNucleus support:
Then turn on Auto-Enhancement:
DataNucleus' enhancer uses the domain object model’s own classpath to reference DataNucleus JARs. So, even though your domain objects are unlikely to depend on DataNucleus, these references must still be present.
See the earlier section on DataNucleus enhancer for details of the contents of the pom.xml
. Chances are it is already set up from running the SimpleApp archetype.
Then, tell DataNucleus to use the project classpath:
When the enhancer runs, it will print out to the console:
If running on Windows then the DataNucleus plugin is very likely to hit the Windows path limit.
To fix this, we configure the enhancer to read from the persistence.xml
file.
As a prerequisite, first make sure that your domain object model has a persistence.xml
file. Then specify the persistence-unit
in the project properties:
On occasion it appears that Eclipse can attempt to run two instances of the DataNucleus enhancer. This is probably due to multiple Eclipse builders being defined; we’ve noticed multiple entries in the Eclipse’s Debug
view:
At any rate, you’ll know you’ve encountered this error if you see the following in the console:
The best solution is to remove DataNucleus support and then to re-add it:
If you consistently hit problems, then the final recourse is to disable the automatic enhancement and to remember to manually enhance your domain object model before each run.
Not ideal, we know. Please feel free to contribute a better solution :-)
The simpleapp archetype automatically provides a .launch
configurations in the webapp
module. You can therefore very simply run the application by right-clicking on one of these files, and choosing "Run As…" or "Debug As…".
The screencast above shows this in action. |
There is nothing to prevent you having multiple domain projects. You might want to do such that each domain project corresponds to a DDD module, thus guaranteeing that there are no cyclic dependencies between your modules.
If you do this, make sure that each project has its own persistence.xml
file.
And, remember also to configure Eclipse’s DataNucleus plugin for these other domain projects.
In this section are a couple of options that will reduce the length of the change code/build/deploy/review feedback loop.
DCEVM enhances the JVM with true hot-swap adding/removing of methods as well as more reliable hot swapping of the implementation of existing methods.
In the context of Apache Isis, this is very useful for contributed actions and mixins and also view models; you should then be able to write these actions and have them be picked up without restarting the application.
Changing persisting domain entities is more problematic, for two reasons: the JDO/DataNucleus enhancer needs to run on domain entities, and also at runtime JDO/DataNucleus would need to rebuild its own metamodel. You may find that adding actions will work, but adding new properties or collections is much less likely to.
For details of setting up DCEVM, see the corresponding section in the IntelliJ documentation.
Project Lombok is an open source project to reduce the amount of boilerplate in your code.
For example, rather than write:
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
you can instead write simply:
@Getter @Setter
private String name;
Under the covers it is implemented as an annotation processor; it basically hooks into the Java compiler so that it can emit additional bytecode (eg for the getter and setter). See here for details of setting up in IntelliJ (Eclipse has very similar support).
Apache Isis supports Project Lombok, in that the annotations that would normally be placed on the getter (namely Property
, @PropertyLayout
, @Collection
, @CollectionLayout
and @MemberOrder
) can be placed on the field instead.
There are plugins for Lombok for maven; it’s just a matter of adding the required dependency. To compile the code within your IDE (eg so that its compiler "knows" that there is, actually, a getter and setter) will require an Lombok plugin appropriate to that IDE. See the Lombok download page for more information.
In the future we might extend/fork Lombok so that it understands Isis' own annotations (ie @Property
and @Collection
)
rather than Lombok’s own @Getter
and `@Setter.
It might also be possible to use Lombok to generate the domain event classes for each member.
This material does not constitute an endorsement; AgileJ Structure Views is not affiliated to Apache Software Foundation in any way. |
AgileJ Structure Views is a commercial product to reverse engineer and visualize Java classes from source code.
The key to using the tool is in developing a suitable filter script, a DSL. You can use the following script as a starting point for visualizing Apache Isis domain models:
// use CTRL+SPACE for completion suggestions
hide all fields
hide setter methods
hide private methods
hide methods named compareTo
hide methods named toString
hide methods named inject*
hide methods named disable*
hide methods named default*
hide methods named hide*
hide methods named autoComplete*
hide methods named choices*
hide methods named title
hide methods named iconName
hide methods named validate*
hide methods named modify*
hide protected methods
hide types annotated as DomainService
hide types named Constants
hide types named InvoicingInterval
hide enums
hide constructors
hide inner types named *Event
hide inner types named *Functions
hide inner types named *Predicates
show getter methods in green
show methods annotated as Programmatic in orange
show methods annotated as Action in largest
hide dependency lines
hide call lines
hide method lines
For more information on AgileJ, see Paul Wells' 8-part tutorial series on Youtube; the first can be found here (view the "show more" comments to click through to other parts).
We provide parameterized templates, for both IntelliJ and Eclipse, to help you write your domain applications.
On IntelliJ we provide both file templates (File > Settings > Editor > File and Code Templates
) and also live templates (File > Settings > Editor > Live Templates
). The former are used to create new classes or files (eg a new domain entity), while the latter are intended to modify an existing file (eg create a new property or add a toString()
method etc).
On Eclipse we provide only the latter sort of template (Windows > Preferences > Java > Editor > Templates).
There are templates for writing Apache Isis domain objects, for writing unit tests (JUnit and JMock), and also for writing Asciidoc documentation (see also the appendix).
The following table lists the templates available to download:
Purpose | IntelliJ file template |
Prefix | IntelliJ live template |
Eclipse template |
---|---|---|---|---|
Domain Objects |
|
|||
JUnit tests |
(none) |
|
||
JMock tests |
(none) |
|
||
Asciidoc |
(none) |
|
(none) |
The most commonly used domain objects (live) templates are also listed on the Apache Isis cheat sheet.
To install in the live templates IntelliJ (Community edition 15), copy to the relevant config/templates
directory, eg:
Windows <User home>\.IdeaIC15\config\templates
Linux ~/.IdeaIC14/config/templates
Mac OS ~/Library/Preferences/IdeaIC15/templates
If using the Ultimate edition, the directory is .IntelliJIdea15
rather than IdeaIC15
.
To install the file templates, use File > Import Settings
.
To install in Eclipse, go to Windows > Preferences > Java > Editor > Templates
and choose Import
.
For the live templates, enter the prefix in the editor (is
, ju
, jm
) and the IDE will list all available templates
in that category.
For the file templates (IntelliJ only), these are available from File > New
.
TODO |
The Apache Isis Maven plugin defines three goals:
validate
Use to verify at build time that the metamodel of an application is valid. This runs the MetaModelValidator
that is also run when the application is started up.
swagger
Uses the SwaggerService
to generate Swagger spec files that describe the public and/or private RESTful APIs exposed by the RestfulObjects viewer.
xsd
Uses the JaxbService
to generate XSD schemas from any JAXB-annotated view models/DTOs.
This is instead of and preferable to using the JAXB schemagen tool, because it uses the framework’s support (via @XmlJavaValueType
) to translate any references to domain objects into OidDto
s (as defined by the Apache Isis common schema).
The validate
goal is by default bound to the test
phase, and the swagger
goal is by default bound to the package
phase; both are typically of your application’s dom
sub-module. The xsd
goal meanwhile defaults to the generate-resources
phase, and this is generally used in a completely separate sub-module. An example can be found in the (non-ASF) Isis addons' todoapp example app; the separate submodule that uses the xsd
goal is (also) called todoapp-xsd
.
All of these goals require an AppManifest
to point the plugin at, so that
it knows how to bootstrap an Isis runtime. This is discussed below, followed by sections on configuring the two goals.
AppManifest
As noted in the introduction, all the goals require an AppManifest
to point the plugin at, so that it knows how to bootstrap an Isis runtime.
This can be extremely minimal. For example, the SimpleApp's manifest is:
package domainapp.dom;
...
public class DomainAppDomManifest implements AppManifest {
@Override
public List<Class<?>> getModules() {
return Arrays.asList(
DomainAppDomainModule.class // domain (entities and repositories)
);
}
@Override
public List<Class<?>> getAdditionalServices() { return Collections.emptyList(); }
@Override
public String getAuthenticationMechanism() { return null; }
@Override
public String getAuthorizationMechanism() { return null; }
@Override
public List<Class<? extends FixtureScript>> getFixtures() { return null; }
@Override
public Map<String, String> getConfigurationProperties() { return null; }
}
where DomainAppDomainModule
simply identifies the package for the manifest to search under:
package domainapp.dom;
public final class DomainAppDomainModule { }
As you’ll see below, the configuration for each of the goals both refer to this app manifest.
validate
goalThe Apache Isis programming model requires that a number of naming conventions are followed.
For example, the validator will detect any orphaned supporting methods (eg hideXxx()
) if the corresponding property
or action has been renamed or deleted but the supporting method was not also updated. Another example is that a class
cannot have a title specified both using title()
method and also using @Title
annotation.
When running the application these are enforced by the MetaModelValidator
component that detects these errors, failing fast.
The purpose of the validate
goal of the isis-maven-plugin
is to enforce these naming conventions at build time,
typically enforced by way of a continuous integration server.
The validate
goal defines a single property:
appManifest
- fully qualified class name for the app manifest used to bootstrap the application (see discussion above)
The sections below explain how to configure the plugin within an app.
The instructions given here relate to |
dom
submoduleUpdate the pom.xml
(in your project’s dom
module):
<profile>
<id>isis-validate</id>
<activation>
<property>
<name>!skip.isis-validate</name> (1)
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.isis.tool</groupId>
<artifactId>isis-maven-plugin</artifactId>
<version>${isis.version}</version> (2)
<configuration>
<appManifest>domainapp.dom.DomainAppDomManifest</appManifest> (3)
</configuration>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>simpleapp-dom</artifactId> (4)
<version>${project.version}</version>
</dependency>
<!-- workaround to avoid conflict with plexus-default -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>16.0.1</version>
</dependency>
</dependencies>
<executions>
<execution>
<phase>test</phase>
<goals>
<goal>validate</goal> (5)
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
1 | the profile is active by default, though can be disabled using -Dskip.isis-validate |
2 | set to 1.10.0 (or any later version) |
3 | the manifest discussed previously; adjust as required |
4 | the dom module for the project; adjust as required |
5 | binds the plugin’s validate goal to the Maven test lifecycle phase (ie the goal will be called when mvn test is run). |
The plugin is activated by default, so is run simply using:
mvn test
This will run any tests, and then also - because the plugin is activated by the isis-validate
property and bound to the test
phase, will run the plugin’s validate
goal.
If for any reason you want to disable the validation, use:
mvn test -Dskip.isis-validate
In the SimpleApp application the SimpleObject
defines an updateName
action. This has a supporting method:
public SimpleObject updateName( ... ) { ... }
public String default0UpdateName() { ... }
We can introduce an error by misspelling the supporting method, for example:
public String default0XUpdateName() { ... }
Running mvn test
then generates this output:
[error]
[error]
[error]
[error] domainapp.dom.simple.SimpleObject#default0XUpdateName: has prefix default, is probably a supporting method for a property, collection or action. If the method is intended to be an action, then rename and use @ActionLayout(named="...") or ignore completely using @Programmatic
[error]
[error]
[error]
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] Simple App ......................................... SUCCESS [ 0.087 s]
[INFO] Simple App DOM ..................................... FAILURE [ 4.182 s]
[INFO] Simple App Fixtures ................................ SKIPPED
[INFO] Simple App Application ............................. SKIPPED
[INFO] Simple App Integration Tests ....................... SKIPPED
[INFO] Simple App Webapp .................................. SKIPPED
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] ...
[ERROR] Failed to execute goal org.apache.isis.tool:isis-maven-plugin:1.12.0-SNAPSHOT:validate (default) on project simpleapp-dom: 1 problems found. -> [Help 1]
If one were to attempt to run the application, the same error would appear in the log files on startup (and the application would not boot).
It is also possible to customize the validation, explained here. For example, you could enforce project-specific conventions by implementing a custom MetaModelValidator
, and registering using a configuration property.
To support this using AppManifest`s, override its `getConfigurationProperties()
method:
public class DomainAppDomManifest implements AppManifest {
...
public Map<String, String> getConfigurationProperties() {
final Map<String, String> map = Maps.newTreeMap();
map.put("isis.reflector.validator","com.mycompany.myapp.MyMetaModelValidator");
return map;
}
}
The 1.9.0
version of the plugin requires slightly different configuratoin. Rather than using an AppManifest
, instead the configuration directory containing isis.properties
is specified:
<profile>
<id>isis-validate</id>
<activation>
<activeByDefault>false</activeByDefault> (1)
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.isis.tool</groupId>
<artifactId>isis-maven-plugin</artifactId>
<version>1.9.0-SNAPSHOT</version>
<configuration>
<isisConfigDir>../webapp/src/main/webapp/WEB-INF</isisConfigDir> (2)
</configuration>
<dependencies>
<dependency>
<groupId>org.apache.isis.example.application</groupId>
<artifactId>simpleapp-dom</artifactId>
<version>1.9.0-SNAPSHOT</version>
</dependency>
<!-- workaround to avoid conflict with plexus-default -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>16.0.1</version>
</dependency>
</dependencies>
<executions>
<execution>
<phase>test</phase>
<goals>
<goal>validate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
1 | activated using the -P profile flag rather than a -D system property |
2 | specify the isisConfigDir directory (containing the isis.properties file). |
To use the 1.9.0
version, use:
mvn -P isis-validate test
Note that the |
swagger
goalThe swagger
goal of the isis-maven-plugin
uses the SwaggerService
to
generate Swagger spec files to describe the public and/or private RESTful APIs exposed by the RestfulObjects viewer.
These spec files, once generated, can then be used in the build pipeline to generate client-side stubs, typically using Swagger’s own swagger-codegen-maven plugin.
The swagger
goal defines the following properties:
appManifest
- fully qualified class name for the app manifest used to bootstrap the application (see discussion above)
fileNamePrefix
- (optional) a prefix to the generated file names (is suffixed by the requested visibilities, see below).
Defaults to swagger
.
visibilities
- (optional) list of required visibilities.
Defaults to [PUBLIC
, PRIVATE
] (meaning that two spec files will be created).
format
- (optional) which format to generate, either JSON
or YAML
.
Defaults to JSON
.
output
- (optional) subdirectory under the target
directory to generate the swagger spec files
Defaults to generated-resources/isis-swagger
dom
submoduleUpdate the pom.xml
(in your project’s dom
module):
<profile>
<id>isis-swagger</id>
<activation>
<property>
<name>!skip.isis-swagger</name> (1)
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.isis.tool</groupId>
<artifactId>isis-maven-plugin</artifactId>
<version>${isis.version}</version> (2)
<configuration>
<appManifest>domainapp.dom.DomainAppDomManifest</appManifest> (3)
<visibilities> (4)
<visibility>PUBLIC</visibility>
<visibility>PRIVATE</visibility>
</visibilities>
<format>JSON</format> (5)
<fileNamePrefix>swagger</fileNamePrefix> (5)
</configuration>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>simpleapp-dom</artifactId> (6)
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>16.0.1</version>
</dependency>
</dependencies>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>swagger</goal> (7)
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
1 | the profile is active by default, though can be disabled using -Dskip.isis-swagger |
2 | set to 1.11.0 (or any later version) |
3 | the manifest discussed previously; adjust as required |
4 | the visibilities to create (one swagger spec file per visibility listed) |
5 | which file format to generate the spec files as. |
6 | the dom module for the project; adjust as required |
7 | binds the plugin’s swagger goal to the Maven package lifecycle phase (ie the goal will be called when mvn package is run). |
The plugin is activated by default, so is run simply using:
mvn package
xsd
goalThe xsd
goal of the isis-maven-plugin
uses the JaxbService
to
generate XSD schemas from any JAXB-annotated view model/DTOs.
This is instead of and preferable to using the JAXB schemagen
tool, because it uses the framework’s support (via
@XmlJavaValueType
) to translate any references to domain
objects into OidDto
s (as defined by the Apache Isis common schema).
The xsd
goal defines the following properties:
appManifest
- fully qualified class name for the app manifest used to bootstrap the application (see discussion above)
jaxbClasses
- a list of JAXB-annotated view model classes;
output
- (optional) subdirectory under the target
directory to generate the XSDs
Defaults to generated-resources/isis-xsd
separate
- (optional) whether to create separate directories for each JAXB-class.
Defaults to false
. Most DTO classes will reference one another or the common schema. Normally it’s fine to merge all these XSDs together. This property, if set, results in each a separate directory for each generation of its XSD or XSDs.
As a convenience to any (Java) consumers, the XSDs generated from the view models can then in turn be generated into DTOs. The original view models and these DTOs are similar but not identical: while the view models can only be used within the Isis application (they may reference underlying domain entities) whereas the DTO classes generated from the XSDs can be used standalone, eg by a Java subscriber running on an ESB such as Apache Camel.
The rest of this section explains how to configure a new xsd
submodule that uses the isis-maven-plugin
along with
other standard plugins in order to generate both XSDs and DTOs. The pom.xml
described below uses Maven profiles
to separate out these two responsibilities.
xsd
submoduleWe recommend creating a new submodule that will perform the following build steps:
run the xsd
goal (in the generate-resources
phase) to generate the XSDs from the specified view model/DTOs
use the maven-assembly-plugin to bundle the generated XSD files into a zip file.
use the xjc-gen
to generate corresponding DTO classes from the XSDs.
These are not the same as the original view models; they are provided as a convenience for subscribers to marshall XML documents into Java classes, but running as a standalone process (not part of the Isis app)
These two main responsibilities can then be placed into separate Maven profiles, for better modularity. The diagram below shows the overall design:
For example, here is the pom.xml
file for the (non-ASF)
Isis addons' todoapp example app’s todoapp-xsd
submodule.
First, the usual boilerplate:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.isisaddons.app</groupId>
<artifactId>todoapp</artifactId>
<version>1.12.0-SNAPSHOT</version>
</parent>
<artifactId>todoapp-xsd</artifactId>
<name>Isis Addons ToDoApp XSD</name>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>todoapp-app</artifactId> (1)
</dependency>
</dependencies>
<profiles>
<profile>
<id>isis-xsd</id> (2)
...
</profile>
<profile>
<id>xjc</id> (3)
...
</profile>
</profiles>
</project>
1 | depends on the rest of the application’s modules |
2 | XSD generation, to run the xsd goal and then assemble into a zip file; within a profile for modularity |
3 | XJC generation, to run the xjc to generate Java DTO classes from XSDs; within a profile for modularity |
The isis-xsd
profile runs the xsd
goal of the isis-maven-plugin
; these are then zipped up by the assembly plugin:
<profile>
<id>isis-xsd</id>
<activation>
<property>
<name>!skip.isis-xsd</name> (1)
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.isis.tool</groupId>
<artifactId>isis-maven-plugin</artifactId>
<version>${isis.version}</version>
<configuration>
<appManifest>todoapp.dom.ToDoAppDomManifest</appManifest> (2)
<jaxbClasses> (3)
<jaxbClass>todoapp.app.viewmodels.todoitem.v1_0.ToDoItemDto</jaxbClass>
<jaxbClass>todoapp.app.viewmodels.todoitem.v1_1.ToDoItemDto</jaxbClass>
</jaxbClasses>
</configuration>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>todoapp-dom</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> (4)
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>16.0.1</version>
</dependency>
</dependencies>
<executions>
<execution>
<phase>generate-sources</phase> (5)
<goals>
<goal>xsd</goal> (6)
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId> (7)
<version>2.5.3</version>
<configuration>
<descriptor>src/assembly/dep.xml</descriptor> (8)
</configuration>
<executions>
<execution>
<id>create-archive</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
1 | enabled unless skip.isis-xsd property specified |
2 | specify the app manifest to bootstrap the Isis runtime within the maven plugin |
3 | enumerate all JAXB-annotated view models |
4 | workaround to avoid conflict with plexus-default |
5 | by default is bound to generate-resources , but bind instead to generate-sources if also running the xjc profile: the XSD are an input to xjc , but it is bound by default to generate-sources and the generate-sources phase runs before the generate-resources . |
6 | run the xsd goal |
7 | define the assembly plugin |
8 | assembles the XSD schemas into a zip file, as defined by the dep.xml file (see below). |
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2
http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>xsd</id>
<formats>
<format>zip</format>
</formats>
<fileSets>
<fileSet>
<directory>${project.build.directory}/generated-resources/isis-xsd</directory> (1)
<outputDirectory>/</outputDirectory>
</fileSet>
</fileSets>
</assembly>
1 | the location that the xsd goal writes to. |
The xjc
profile reads the XSD generated by the xsd
goal, and from it generates Java DTOs. Note that this isn’t
round-tripping: the original view model is only for use within the Isis app, whereas the DTO generated from the XSDs
is for use in a standalone context, eg in a Java subscriber on an event bus.
The xjc
profile is defined as:
<profile>
<id>xjc</id>
<activation>
<property>
<name>!skip.xjc</name> (1)
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.12.3</version>
<executions>
<execution>
<id>xjc-generate</id>
<phase>generate-sources</phase>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<removeOldOutput>true</removeOldOutput>
<schemaDirectory> (2)
target/generated-resources/isis-xsd/viewmodels.app.todoapp/todoitem
</schemaDirectory>
<schemaIncludes> (3)
<schemaInclude>v1_0/todoitem.xsd</schemaInclude>
<schemaInclude>v1_1/todoitem.xsd</schemaInclude>
</schemaIncludes>
<catalog>src/main/resources/catalog.xml</catalog> (4)
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId> (5)
<version>1.9.1</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>target/generated-sources/xjc</source> (6)
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
1 | enabled unless skip.xjc property specified |
2 | specifies the directory that the XSD schemas were generated to by the isis-maven-plugin |
3 | specify each of the XSDs to be processed |
4 | catalog file indicates the location of the referenced common schema XSDs. |
5 | the build-helper-maven-plugin adds the Java source generated by the xjc plugin so that it can be compiled and
packaged as any other code |
6 | the location that the xjc plugin generates its source code. |
The referenced catalog.xml
file instructs the xjc
plugin how to resolve referenced schema locations. Only a
reference for the Apache Isis common schema is likely to be needed:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE catalog
PUBLIC "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN"
"http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd">
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
<public publicId="http://isis.apache.org/schema/common"
uri="http://isis.apache.org/schema/common/common.xsd"/> (1)
</catalog>
1 | resolve the common schema from the Apache Isis website |
The plugin is activated by default, so is run simply using:
mvn package
This will generate the XSDs, the DTOs from the XSDs, and package up the XSDs into a ZIP file and the generated DTO class files into a regular JAR package.
If for any reason you want to disable the generation of the DTOs, use:
mvn package -Dskip.xjc
If you want to disable the generation of both the XSDs and the DTOs, use:
mvn package -Dskip.xjc -Dskip.isis-xsd
The Apache Isis source code lives in a git repo.
The easiest place to get hold of command-line git is probably the github download page.
On Windows, this also installs the rather good mSysGit Unix shell. We recommend that you enable git for both the mSysgit and the Windows command prompt:
Once git is installed, the two main command line tools to note are:
git
command line tool
gitk
for viewing the commit history
If using Windows, note that github also have a dedicated Windows client. With a little hacking around, it can also be made to work with non-github repositories.
If using Mac, you might also want to check out Atlassian’s Sourcetree.
First, clone the Apache Isis repo.
If you are a committer, then clone from the Apache read/write repo:
git clone https://git-wip-us.apache.org/repos/asf/isis.git
If you are not a committer, please see the contributing page for details on which repo to clone from.
Next up is to configure your user name and password; see also Apache’s git docs:
git config user.name "<i>My Name Here</i>"
git config user.email <i>myusername@apache.org</i>
Next, configure the core.autocrlf
so that line endings are normalized to LF (Unix style) in the rep; again see Apache’s git page:
on Windows, use:
git config core.autocrlf true
on Mac/Linux, use:
git config core.autocrlf input
The Windows setting means that files are converted back to CRLF on checkout; the Mac/Linux setting means that the file is left as LF on checkout.
We also recommend setting core.safecrlf
, which aims to ensure that any line ending conversion is repeatable. Do this on all platforms:
git config core.safecrlf true
Note that these settings are supplemented in the repo by the .gitattributes
file and that explicitly specifies line handling treatment for most of the common file types that we have.
Next, we recommend you setup this a refspec so that you can distinguish remote tags from local ones. To do that, locate the [remote "origin"]
section in your .git/config
and add the third entry shown below:
[remote "origin"]
url = ... whatever ...
fetch = ... whatever ...
fetch = +refs/tags/*:refs/tags/origin/*
This will ensure that a git fetch
or git pull
places any remote tags under origin/xxx. For example, the`isis-1.0.0`tag on the origin will appear under`origin/isis-1.0.0
.
If you don’t use git outside of Apache, you can add the --global
flag so that the above settings apply for all repos managed by git on your PC.
Three commands of git that in particular worth knowing:
git help command
will open the man page in your web browser
git gui
will open up a basic GUI client to staging changes and making commits.
gitk --all
will open the commit history for all branches. In particular, you should be able to see the local master
, which branch you are working on (the HEAD
), and also the last known position of the master
branch from the central repo, called origin/master
.
You might also want to explore using a freely available equivalent such as Atlassian SourceTree.
For further reading, see:
Apache Isis is compatible with Java 7 and Java 8. For every-day use, the framework is usually compiled against Java 8.
Releases however are cut using Java 7, leveraging the link :http://maven.apache.org/plugins/maven-toolchains-plugin/[Maven toolchains plugin]).
Therefore install either/both of Java 7 JDK and Java 8 JDK. Note that the JRE is not sufficient.
If you intend to contribute back patches to Apache Isis, note that while you can develop using Java 8 within your IDE, be sure not to use any Java 8 APIs. |
If you are a committer that will be performing releases of Apache Isis, then you must configure the toolchains plugin so that releases can be built using Java 7.
This is done by placing the toolchains.xml
file in ~/.m2
directory. Use the following file as a template,
adjusting paths for your platform:
<?xml version="1.0" encoding="UTF8"?>
<toolchains>
<toolchain>
<type>jdk</type>
<provides>
<version>1.8</version>
<vendor>oracle</vendor>
</provides>
<configuration>
<jdkHome>/usr/lib64/jvm/jdk1.8.0_65</jdkHome>
<!--
<jdkHome>c:\Program Files\Java\jdk1.8.0_65</jdkHome>
-->
</configuration>
</toolchain>
<toolchain>
<type>jdk</type>
<provides>
<version>1.7</version> (1)
<vendor>oracle</vendor>
</provides>
<configuration>
<jdkHome>/usr/lib64/jvm/jdk1.7.0_79</jdkHome>
<!--
<jdkHome>c:\Program Files\Java\jdk1.7.0_79</jdkHome>
-->
</configuration>
</toolchain>
</toolchains>
1 | The Apache Isis build is configured to search for the (1.7, oracle ) JDK toolchain. |
The Apache Isis parent pom.xml
activates this plugin whenever the apache-release
profile is enabled.
Install Maven 3.0.x, downloadable here.
Set MAVEN_OPTS
environment variable:
export MAVEN_OPTS="-Xms512m -Xmx1024m"
Previously we suggested |
To build the source code from the command line, simply go to the root directory and type:
mvn clean install
The first time you do this, you’ll find it takes a while since Maven needs to download all of the Apache Isis prerequisites.
Thereafter you can speed up the build by adding the -o
(offline flag). To save more time still, we also recommend that you build in parallel. (Per this blog post), you could also experiment with a number of JDK parameters that we’ve found also speed up Maven:
export MAVEN_OPTS="-Xms512m -Xmx1024m -XX:+TieredCompilation -XX:TieredStopAtLevel=1"
mvn clean install -o -T1C
For the most part, though, you may want to rely on an IDE such as Eclipse to build the codebase for you. Both Eclipse and Idea (12.0+) support incremental background compilation.
When using Eclipse, a Maven profile is configured such that Eclipse compiles to target-ide
directory rather than the usual target
directory. You can therefore switch between Eclipse and Maven command line without one interfering with the other.
Apache Isis configures the OWASP dependency check Maven plugin to determine whether the framework uses libraries that are known to have security vulnerabilities.
To check, run:
mvn org.owasp:dependency-check-maven:aggregate -Dowasp
This will generate a single report under target/dependency-check-report.html
.
The first time this runs can take 10~20 minutes to download the NVD data feeds. |
To disable, either run in offline mode (add -o
or --offline
) or omit the owasp
property.
Apache Isis configures the jdeps maven plugin to check for any usage of internal JDK APIs. This is in preparation for Java 9 module system (Jigsaw) which will prevent such usage of APIs.
To check, run:
mvn clean install -Djdeps
This will fail the build on any module that currently uses an internal JDK API.
At the time of writing the |
This page explains how you can contribute to Apache Isis. You’ll probably also want set up your IDE and learn how to build Apache Isis.
Thanks for considering to help out, your contributions are appreciated!
Apache Isis' source code is hosted in an Apache git repo (https, http), with a clone on github (https, or ssh: git@github.com:apache/isis.git
.
As you might imagine, only committers are permitted to push changes to the central git repo. As a contributor, we recommend that you fork the apache/isis repo in github, and then use your fork as a way of publishing your patches for the Apache Isis committers to apply.
The diagram below illustrates the process:
That is:
as a one-time activity, you fork the github.com/apache/isis repo into your own fork on github.com
as a one-time activity, you clone your fork to your local computer
you set the github.com/apache/isis as your upstream branch; this will allow you to keep your local clone up-to-date with new commits
note the asymmetry here: the upstream
repo (the Apache github repo) is not the same as the origin
repo (your fork).
you work on your changes locally; when done, you push them to your github fork
to contribute back a change, raise a JIRA ticket, and ensure your commit message is in the form: ISIS-nnnn: …
so that changes can be tracked (more discussion on this point below). In any case, before you decide to start hacking with Apache Isis, it’s always worth creating a ticket in JIRA and then have a discussion about it on the mailing lists.
Use github to raise a pull request for your feature
An Apache Isis committer will review your change, and apply it if suitable.
As an alternative, you may decide to clone directly from github.com/apache/isis rather than create your own fork:
In this case your upstream
repo is the same as your origin
repo, which might seem more straightforward. On the other hand, if you go this route then you’ll need create patches locally and attach them to the JIRA ticket.
For the Apache Isis committers it really doesn’t matter which route you take, so go with whatever’s most comfortable.
If you choose to create your own fork then you’ll need an account on github.com. You then fork simply by pressing the "Fork" button:
An account isn’t needed if you just clone straight from the github.com/apache/isis.
Whether you’ve forked or not, you then need to clone the repo onto your computer. Github makes this very easy to do:
for Windows users, we suggest you use github’s 'Clone in Windows' feature
for Mac/Linux users, create a clone from the command line:
Again, the info is easily found in the github page:
If you’ve created your own fork, then you need to add the upstream
remote to the github.com/apache/isis. This remote is traditionally called upstream
. You should then arrange for your master
branch to track the upstream/master
remote branch:
If you didn’t create your own fork, you can omit the above step. Either way around, you can now fetch new commits using simply:
git fetch
Although with git your commits are always performed on your local repo, those commit messages become public when the patch is applied by an Apache Isis committer. You should take time to write a meaningful commit message that helps explain what the patch refers to; if you don’t then there’s a chance that your patch may be rejected and not applied. No-one likes hard work to go to waste!
We therefore recommend that your commit messages are as follows [1]:
ISIS-999: Make the example in CONTRIBUTING imperative and concrete
Without this patch applied the example commit message in the CONTRIBUTING
document is not a concrete example. This is a problem because the
contributor is left to imagine what the commit message should look like
based on a description rather than an example. This patch fixes the
problem by making the example concrete and imperative.
The first line is a real life imperative statement with a ticket number
from our issue tracker. The body describes the behavior without the patch,
why this is a problem, and how the patch fixes the problem when applied.
Once your git repo is setup, the next thing you’ll most likely want to do is to setup your development environment. See here for more details.
If you are working without a github fork of Apache Isis, then you can create the patches from your own local git repository.
As per this stackoverflow question, create the patch using git format-patch
:
git format-patch -10 HEAD --stdout > 0001-last-10-commits.patch
Here -10
is the last 10 commits you have done. You need to change that integer according to the commits you need to apply into the patch.
Assuming you’re development environment is all setup, let’s walk through how you might make contribute a patch. In this example, suppose that you’ve decided to work on JIRA ticket #123, an enhancement to support Blob/Clob datatypes.
The first thing to do is to make sure your local clone is up-to-date. We do this by retrieving new commits from upstream repo and then merging them as a fast-forward into your local branch.
Irrespective of whether you are using a github fork, the upstream for your local master
branch will be tracking the appropriate remote’s master
branch. So n either case, the same commands work:
Alternatively, you can combine the git fetch
and git merge
and just use git pull
:
<pre>
git checkout master
git pull –ff-only
</pre>
If the merge
or pull
fails, it means that you must have made commits and there have been changes meanwhile on the remote master’s branch. You can use `gitk --all
to confirm. If this fails, see our git cookbook page for a procedure to retrospectively sort out this situation.
We recommend you name topic branches by the JIRA ticket, ie <tt>ISIS-nnn-description</tt>. So let’s create a new branch based off master
and call it "ISIS-123-blobs"
You can confirm the branch is there and is your new HEAD
using either gitk --all
. Alternatively, use the command line:
$ git checkout -b ISIS-123-blobs
The command line prompt should also indicate you are on a branch, isolated from any changes that might happen on the master
branch.
Next, make changes to your files using the usual commands (see also our git cookbook section):
git add
git mv
git rm
git commit
git status
and so on.
Continue this way until happy with the change. Remember to run all your tests on the topic branch (including a full mvn clean install
).
master
Before you can share your change, you should rebase (in other words replay) your changes on top of the master
branch.
The first thing to do is to pull down any changes made in upstream remote’s master
since you started your topic branch:
These are the same commands that you would have run before you created your topic branch. If you use gitk --all
, there’s a good chance that new commits have come in.
Next, we reintegrate our topic branch by rebasing onto master
:
<pre>
git checkout ISIS-123-blobs
git rebase master
</pre>
This takes all of the commits in your branch, and applies them on top of the new master
branch. When your change is eventually integrated back in, it will result in a nice clear linear history on the public repo.
If the rebase fails because of a conflict, then you’ll be dumped into REBASE mode. Edit the file that has the conflict, and make the appropriate edits. Once done:
Once the rebase has completed, re-run your tests to confirm that everything is still good.
If you have your own fork, you can now simply push the changes you’ve made locally to your fork:
This will create a corresponding branch in the remote github repo. If you use gitk --all
, you’ll also see a remotes/origin/ISIS-123-blobs
branch.
Then, use github to raise a pull request. Pull requests sent to the Apache GitHub repositories will forward a pull request e-mail to the dev mailing list. You’ll probably want to sign up to the dev mailing list first before issuing your first pull request (though that isn’t mandatory).
The process to raise the pull request, broadly speaking:
Open a web browser to your github fork of isis
Select your topic branch (pushed in the previous step) so that the pull request references the topic branch.
Click the Pull Request
button.
Check that the Apache Isis mailing list email came through.
To double check that your pull request is accepted, update your master
branch from the upstream
remote:
You can then use gitk --all
(or git log
if you prefer the command line) to check your contribution has been added.
You can now delete your topic branch and remove the branch in your github:
Finally, you might want to push the latest changes in master back up to your github fork. If so, use:
If your pull request is rejected, then you’ll need to update your branch from the main repository and then address the rejection reason.
You’ll probably also want to remove the remote branch on github:
git push origin –delete ISIS-123-blobs
… and continue as before until you are ready to resubmit your change.
[1] inspiration for the recommended commit format comes from the puppet project’s contributing page.
This chapter pulls together various policy documents relating to the development of Apache Isis'.
Starting from v1.0.0, Apache Isis has adopted semantic versioning for its versioning policy.
Version numbers are in the form x.y.z
:
x is bumped up whenever there a breaking API change
y is bumped up whenever there is a new feature that does not break API
z is bumped up for minor bug fixes.
This scheme would be adopted for both core and components.
Version ranges may not be used. If necessary, end-users can use <dependencyManagement
elements to have combine components built against different versions of core.
That said, this can introduce instability and so generally we recommend that end-users configure the maven-enforcer-plugin
and its DependencyConvergence rule. This will help avoid "jar hell" (components having conflicting dependencies of core).
If there is a conflict, we would ask that end-users engage with Apache Isis committers to have an updated version of the component(s) pushed out.
These notes recommend how contributors should work with git. To understand these notes, the only real concepts that you need to grok are:
git commits form an acyclic graph, with each commit pointing to its parent commit (or commits, if a merge)
a branch is merely a pointer to one of these commits; git calls the main branch master
git commits happen in two steps: first they are added to the index (also called the staging area), then they are committed.
For more background reading, see:
Pro Git book (free in electronic form)
git reset demystified - differentiating the working directory vs index/staging area
And, of course, there is loads of good advice on stackoverflow.com
There are many ways of using Git, but the Apache Isis committers have adopted the following workflow:
create a topic branch for a feature
git checkout -b ISIS-999
periodically, push the branch to origin (for safekeeping):
git push origin ISIS-999
rebase
the topic branch periodically on master.
How often you do this will depend on whether you are collaborating with others on the feature. You need to ensure that your co-worker has no outstanding work before you do this; otherwise it’ll create merge conflict hell for them:
git checkout master
git pull
git checkout ISIS-999
git rebase master
git push origin ISIS-999 --force
when feature is complete, rebase once more (as above), then switch to master and perform a merge --no-ff
:
git checkout master
git merge --no-ff ISIS-999
finally, remove the branch
git branch -d ISIS-999
git push origin --delete ISIS-999
This way of working gives us the full history on the branch as to what the thought processes were for the feature, but only a single commit on to master
to see the ultimate impact of the changes (acting a bit like a summary).
The minimum we expect in a commit messages is:
ISIS-nnn: brief summary here
- optionally, longer details
- should be written here
- in bullet points
where ISIS-nnn
is a ticket raised in our JIRA issue tracker.
For non-committers we typically expect more detail again; see the contributing page for the longer format recommended for contributors to use.
Apache Isis' documentation (meaning the website and the users' guide, the reference guide and this contributors' guide) is written using Asciidoc, specifically the Asciidoctor implementation.
The website and guides are created by running build tools (documented below) which create the HTML version of the site and guides. You can therefore easily check the documentation before raising a pull request (as a contributor) or publishing the site (if a committer).
Publishing is performed by copying the generated HTML to a different git repository (isis-site). This is synced by ASF infrastructure over to isis.apache.org.
And to help write the Asciidoc text itself, we provide some templates.
The (Asciidoc) source code can be found at adocs/documentation
(relative to root). Online you’ll find it cloned to github here.
For documents with inclusions, use '_' to separate out the logical hierarchy:
xxx-xxx/xxx-xxx.adoc
_xxx-xxx_ppp-ppp.adoc
_xxx-xxx_qqq-qqq.adoc
_xxx-xxx_qqq-qqq_mmm-mmm.adoc
_xxx-xxx_qqq-qqq_nnn-nnn.adoc
Any referenced images should be in subdirectories of the images
directory:
xxx-xxx/images/.
/ppp-ppp/.
/qqq-qqq/.
/mmm-mmm
/nnn-nnn
And similarly any resources should be in the resources
subdirectory:
xxx-xxx/resources/.
ppp-ppp/.
qqq-qqq/.
/mmm-mmm/
/nnn-nnn/
We highly recommend that you install the (IntelliJ) live templates for Asciidoctor, as described in IDE templates. These provide a large number of helper templates.
An appendix lists all the templates available, demonstrating their intended usage and output.
To (re)build the documentation locally prior to release, change into the adocs/documentation
directory and use:
mvn clean compile
The site will be generated at target/site/index.html
.
You could then use a web server such as Python’s SimpleHTTPServer to preview (so that all Javascript works correctly). However, instead we recommend using instant preview, described next.
The ruby script, monitor.rb
emulates the mvn compile
command, regenerating any changed Asciidoctor files to the relevant target/site
directory. Moreover if any included files are changed then it rebuilds the parent (per the above naming convention).
To setup:
download and install ruby 2.0.0, from http://rubyinstaller.org/downloads/
download devkit for the Ruby 2.0 installation, also from http://rubyinstaller.org/downloads/. Then follow the installation instructions on their wiki
We use Ruby 2.0 rather than 2.1 because the wdm gem (required to monitor the filesystem if running on Windows) is not currently compatible with Ruby 2.1. |
To download the required Ruby dependencies, use:
gem install bundler
bundle install
To run, we typically just use:
sh monitor.sh
This script simply runs mvn clean compile && ruby monitor.rb -b
. The mvn
command performs a clean rebuild of the site, and then the ruby script monitors for any further changes under src/main/asciidoc
.
The script also starts up a web server on port 4000 so you can review results. If any .adoc
changes, then the appropriate HTML will be regenerated. And, if any new assets (CSS, images etc) are added, they will be copied across. The -b
flag passed through means that the script also starts a web browser pointing at the newly generated docs.
The monitor.rb
script has a couple of other options, use -h
flag for usage:
ruby monitor.rb -h
which should print:
usage: monitor.rb [options]
-p, --port port (default: 4000)
-b, --browser launch browser
-h, --help help
Only Apache Isis committers can publish to isis.apache.org. We’ve decided to include these procedures here here (rather than put them in the Committers' Guide), just to keep things together.
The generated site is published by copying into the content/
directory of the isis-site git repo. You therefore need to check this out this repo.
The procedure assumes that two git repos (for isis itself and for isis-site) are checked out into the same parent directory, eg:
/APACHE/
isis/ # checkout of isis.git
adocs/
documentation/
README.adoc # this file you are reading right now
...
isis-site/ # checkout of isis-site.git
content/ # the published website
If this isn’t the case, then it is possible to override the relative directory by passing in a system property to the mvn goal; see below.
You also need to know that ASF’s publishing script work from the 'asf-site' branch, NOT from the 'master' branch. Therefore, in the isis.git
repo site:
git checkout asf-site
Back in the adocs/documentation
directory of the main isis-git.repo
, to copy the generated documents to the isis-site.git
repo, run:
mvn clean package
This deletes the entire content of contents
, and replaces with the content under target/site
. It also fixes up line endings, standardizing on unix-style LFs.
If you have checked out the |
To copy and to also commit the generated documents to the isis-site.git
repo , run:
sh publish.sh "ISIS-nnnn: a custom commit message"
Behind the scenes this just calls mvn clean install -Dmessage=…
.
Pushing the commits (in the isis-site.git
directory, of course) will publishing the changes:
git push
Double check at isis.apache.org.
This appendix describes the commands often used while working with git. In addition to these basic commands, please make sure you have read:
To modify existing files:
git add filename
git commit -m "ISIS-nnn: yada yada"
The git add
command adds the changes to the file(s) to the git index (aka staging area). If you were to make subsequent changes to the file these would not be committed.
The git commit
takes all the staged changes and commits them locally. Note that these changes are not shared public with Apache Isis' central git repo.
You can combine these two commands using -am
flag to git commit:
git commit -am "ISIS-nnn: yada yada"
To add a new file:
git add .
git commit -m "ISIS-nnn: yada yada"
Note that this sequence of commands is identical to modifying an existing file. However, it isn’t possible to combine the two steps using git commit -am
; the git add
is always needed when adding new files to the repo.
To delete a file:
git rm filename
git commit -m "ISIS-nnn: yada yada"
To rename or move a file:
git mv <i>filename</i> <i>newfilename</i>
git commit -m "ISIS-nnn: yada yada"
The contributing page describes the workflow for non-committers. The Git policy page describes a workflow for Apache Isis committers.
If committing to a local branch, the changes are still just that: local, and run risk of a disk failure or other disaster.
To create a new, similarly named branch on the central repo, use:
git push -u origin <i>branchname</i>
Using gitk --all
will show you this new branch, named origin/branchname.
Thereafter, you can push subsequent commits using simply:
git push
Doing this also allows others to collaborate on this branch, just as they would for master
.
When, eventually, you have reintegrated this branch, you can delete the remote branch using:
git push origin --delete <i>branchname</i>
If you are working on something but are not ready to commit, then use:
git stash
If you use gitk --all
then you’ll see new commits are made that hold the current state of your working directory and staging area.
You can then, for example, pull down the latest changes using git pull --rebase
(see above).
To reapply your stash, then use:
git stash pop
Note that stashing works even if switching branches
Put file patterns into .gitignore
. There is one at the root of the git repo, but they can additionally appear in subdirectories (the results are cumulative).
See also:
Suppose you committed to master
, and then pushed the change, and then decided that you didn’t intend to do that:
C1 - C2 - C3 - C4 - C5 - C6 - C7
^
master
^
origin/master
To go back to an earlier commit, first we wind back the local master
:
git reset --hard C5
where C5
is the long sha-id for that commit.
This gets us to:
C1 - C2 - C3 - C4 - C5 - C6 - C7
^
master
^
origin/master
Then, do a force push:
git push origin master --force
If this doesn’t work, it may be that the remote repo has disabled this feature. There are other hacks to get around this, see for example here.
master
branchIf at any time the git pull
from your upstream fails, it most likely means that you must have made commits on the master
branch. You can use gitk --all
to confirm; at some point in time both master
and origin\master
will have a common ancestor.
You can retrospectively create a topic branch for the work you’ve accidentally done on master
.
First, create a branch for your current commit:
git branch <i>newbranch</i>
Next, make sure you have no outstanding edits. If you do, you should commit them or stash them:
git stash
Finally, locate the shaId of the commit you want to roll back to (easily obtained in gitk -all
), and wind master
branch back to that commit:
git checkout master
git reset --hard <i>shaId</i> # move master branch shaId of common ancestor
One of our committers, Alexander Krasnukhin, has put together some git scripts to help his workflow. Using one of these, git prefix
, you can just commit with proper message without bothering about prefix and add prefix only in the end before the final push.
For example, to prefix all not yet prefixed commits master..isis/666
with ISIS-666
prefix, use:
git prefix ISIS-666 master..isis/666
You can grab this utility, and others, from this repo.
This appendix lists the (IntelliJ) live templates available for writing documentation using Asciidoc. Instructions for installing the templates can be found here.
In the examples below the text xxx
, yyy
, zzz
are correspond to template variables (ie placeholders).
The Asciidoctor terminology is an "admonition".
Abbrev. | Produces | Example | ||
---|---|---|---|---|
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
Add as a placeholder for documentation still to be written or which is work-in-progress.
Abbrev. | Produces | Example | ||
---|---|---|---|---|
|
NOTE: TODO |
|
||
|
NOTE: WIP - xxx where:
|
|
Cross-references (links) to the various guides
Abbrev. | Produces | Example |
---|---|---|
|
xref:cgcom.adoc#xxx[ttt] a hyperlink to a bookmark within the committers' guide, where:
for example: xref:cgcon.adoc#_cgcom_cutting-a-release[Cutting a release] |
|
xref:cgcom.adoc#xxx[ttt] a hyperlink to a bookmark within the contributors' guide, where: * for example: xref:cgcon.adoc#_cgcon_asciidoc-templates[Asciidoc templates] |
|
|
xref:rgcfg.adoc#xxx[ttt] a hyperlink to a bookmark within configuration properties guide, where: * for example: xref:rgcfg.adoc#_rgcfg_configuring-core[Configuring Core] |
|
|
xref:rgcms.adoc#_rgcms_classes_super_xxx[`xxx`] a hyperlink to the "man page" for a superclass, where: * for example: xref:rgcms.adoc#_rgcms_classes_super_AbstractService[`AbstractService`] |
|
|
xref:rgcms.adoc#_rgcms_classes_utility_xxx[`xxx`] a hyperlink to the "man page" for a utility class, where: * for example: xref:rgcms.adoc#_rgcms_classes_utility_TitleBuffer[`TitleBuffer`] |
|
|
xref:rgcms.adoc#_rgcms_classes_value-types_xxx[`xxx`] a hyperlink to the "man page" for an applib value class, where: * for example: xref:rgcms.adoc#_rgcms_classes_value-types_Blob[`Blob`] |
|
|
xref:rgcms.adoc#_rgcms_methods_prefixes_xxx[`xxx...()`] a hyperlink to the "man page" for a prefixed method, where: * for example: xref:rgcms.adoc#_rgcms_methods_prefixes_disable[`disable...()`] |
|
|
a hyperlink to the "man page" for a reserved method, where: * for example: xref:rgcms.adoc#_rgcms_methods_reserved_title[`title()`] |
|
|
xref:rgant.adoc#_rgant-xxx[`@xxx`</pre>] |
|
|
xref:rgant.adoc#_rgant-xxx_ttt[`@xxx#ttt()`</pre>] |
|
|
a hyperlink to the "man page" for an (API) domain service, where: * for example: xref:rgsvc.adoc#_rgsvc_api_DomainObjectContainer[`DomainObjectContainer`] |
|
|
a hyperlink to the "man page" for an (SPI) domain service, where: * for example: xref:rgsvc.adoc#_rgsvc_spi_ContentMappingService[`ContentMappingService`] |
|
|
xref:ugfun.adoc#xxx[ttt] a hyperlink to a bookmark within the fundamentals users' guide, where: * for example: xref:ugfun.adoc#_ugfun_core-concepts[Core concepts] |
|
|
xref:ugvw.adoc#xxx[ttt] A hyperlink to a bookmark within the Wicket viewer guide, where: * for example: xref:ugvw.adoc#_ugvw_customisation[Customisation] |
|
|
xref:ugvro.adoc#xxx[ttt] A hyperlink to a bookmark within the Restful Objects viewer guide, where: * for example: xref:ugvro.adoc#_ugvro_ro-spec[RestfulObjects specification] |
|
|
xref:ugsec.adoc#xxx[ttt] A hyperlink to a bookmark within the Secrurity guide, where: * for example: xref:ugsec.adoc#_ugsec_shiro-caching[Caching and other Shiro Features] |
|
|
xref:ugtst.adoc#xxx[ttt] A hyperlink to a bookmark within the Testing guide, where: * for example: xref:ugtst.adoc#_ugtst_bdd-spec-support[BDD Spec Support] |
|
|
xref:ugbtb.adoc#xxx[ttt] A hyperlink to a bookmark within the 'Beyond the Basics' user guide, where: * for example: xref:ugbtb.adoc#_ugbtb_deployment_externalized-configuration[Externalized Configuration] |
|
Links to (non-ASF) Isis Addons
Abbrev. | Produces | Example |
---|---|---|
|
(non-ASF) link:http://isisaddons.org[Isis Addons] link to the Isis Addons website. |
(non-ASF) Isis Addons |
|
(non-ASF) http://github.com/isisaddons/isis-app-xxx[Isis addons' xxx</pre>] link to the github repo for an example app from the Isis addons; where:
for example: (non-ASF) http://github.com/isisaddons/isis-app-todoapp[Isis addons' todoapp] |
(non-ASF) Isis addons' todoapp |
|
link to the github repo for a module from the Isis addons; where:
for example: (non-ASF) http://github.com/isisaddons/isis-module-security[Isis addons' security] module |
(non-ASF) Isis addons' security module |
|
link to the github repo for a wicket UI component from the Isis addons; where:
for example: (non-ASF) http://github.com/isisaddons/isis-wicket-gmap3[Isis addons' gmap3 ] wicket extension |
(non-ASF) Isis addons' gmap3 wicket extension |
Abbrev. | Produces | Example |
---|---|---|
|
where:
|
|
|
as for |
|
|
where:
|
|
|
as for |
|
|
where:
|
|
|
as for |
|
|
where:
|
|
|
as for |
Abbrev. | Produces | Example |
---|---|---|
|
image::{_imagesdir}xxx/yyy.png[width="WWWpx",link="{_imagesdir}xxx/yyy.png"] embeds specified image, where:
for example: image::{_imagesdir}wicket-viewer/layouts/estatio-Lease.png[width="300px",link="{_imagesdir}wicket-viewer/layouts/estatio-Lease.png"] |
|
|
as for |
|
|
image::xxx[width="WWWpx",link="xxx"] embeds image from specified URL, where:
|
|
|
as for |
Embedded youtube screencasts
Abbrev. | Produces | Example |
---|---|---|
|
video::xxx[youtube,width="WWWpx",height="HHHpx"] where:
for example: video::bj8735nBRR4[youtube,width="210px",height="118px"] |
|
|
as for |
Abbrev. | Produces | Example |
---|---|---|
|
Table with 3 columns, 3 rows. |
Abbrev. | Produces | Example |
---|---|---|
|
Apache Isis That is, the literal text "Apache Isis". |
Apache Isis |
|
link:xxx[ttt] , where:
for example: link:http://isis.apache.org[Apache Isis website] |
|
|
= anchor:[xxx] defines an inline anchor to any heading, where:
For example: = anchor:[_ugfun_i18n] Internationalization An alternative (more commonly used in our documentation) is to use the [[_ugfun_i18n]] = Internationalization |
|
|
xref:[xxx] cross-reference to any document/anchor, where:
|
|
|
.footnote:[] defines a footnote |
master
branch