Getting Started

Prereqs

You’ll need:

  • Java 8

    Apache Isis hasn’t yet been tested for later versions of Java; the next major version of the framework will target Java 11.

  • Maven 3.x

    Maven 3.5.0 or later is recommended (for its CI/CD support), but you’ll get by okay with earlier versions.

Also recommended:

  • a Java IDE with support for Maven.

    The Apache Isis website has detailed documentation for using IntelliJ and Eclipse.

  • git

    The tutorial includes worked example/solution, provided in a github-hosted repo. This has multiple tags for the various checkpoints. If you want to work from the solution, you’ll need git to pull down the version.

Generate

Use the "Hello World" Maven archetype to generate a running app (adjust groupId and artifactId as necessary):

mvn archetype:generate  \
    -D archetypeGroupId=org.apache.isis.archetype \
    -D archetypeArtifactId=helloworld-archetype \
    -D archetypeVersion=1.16.2 \
    -D groupId=com.mycompany \
    -D artifactId=myapp \
    -D version=1.0-SNAPSHOT \
    -B

cd myapp

Build and run:

mvn clean package jetty:run

and then browse to http://localhost:8080:

index

Explore the Generated App

Although there’s the archetype doesn’t generated much code, there’s still plenty to explore.

Wicket viewer

Follow the "wicket" link and logon using sven/pass.

home page

Use the "Hello World Objects" menu:

hello world objects menu

to:

  • create new objects

  • search by name

  • list all objects

    Note that "list all" is in italics. That’s because this is a so-called "prototype" action; it’s only available when running in prototype (development) mode.

On an object:

object a

perform the following:

  • update its name

  • delete the object

  • create two objects with the same name

Use the "Prototyping" menu:

prototyping menu

to access various built-in functionality. For example, use "HSQL DB Manager" to launch a Swing UI to browse the backend database (we use HSQL DB running in-memory when prototyping). Note that we’ll be exploring the Swagger UI/REST API) below.

Use the tertiary menu (with the user’s name) to view the application’s configuration settings and to logout:

tertiary menu

Use the bookmarks page (top left strip or alt-[ ) to access previously visited domain objects. Use the drop-down menu on the bottom footer as an alternative mechanism.

Restful Objects (Swagger)

Navigate back to http://localhost:8080, and follow the "swagger-ui" link. Enter sven/pass and "prototyping", then reload:

swagger ui

Use the Swagger UI to interact with the domain objects previously created in the Wicket viewer.

For example, follow /services/myapp.HelloWorldObjects/actions/listAll/invoke to list all domain objects.

Use the "Response Content Type" drop-down to obtain different representations of the list.

Pull down github example/solution

This tutorial has an accompanying github repo with multiple tags for the various checkpoints; the first tag is immediately after creating the archetype. We recommend that you pull this down so that - even if you code up all the steps yourself - you can easily get back to a working application if needs be.

To pull down the example:

git clone https://github.com/danhaywood/isis-petclinic-tutorial

and then checkout the first tag:

git checkout tags/010-pull-down-github-example-solution
mvn clean package jetty:run

You can now run the app. If necessary, switch into the "myapp" directory:

cd myapp

and run using:

mvn clean package jetty:run

Set up your dev env

Rather than running and editing from the Maven command line, we recommend that you load the application into an IDE and run from there.

Admittedly, there is 5 or 10 minutes of setup required here.

If you are short of time then you might want to skip this and instead just run the solutions by checking out the various tags and run using "mvn clean package jetty:run".

Do though use an an editor that lets you easily locate files in the filesystem.

Loading the project

Assuming that you are going to use a mainstream IDE, the first bit is to load the files into the IDE. All of the mainstream IDEs make this easy to do: generally open Maven projects just by navigating to the pom.xml. For example, here’s the generated app loaded into IntelliJ:

project loaded into intellij

Compiling the app

DataNucleus includes an annotation processor, so make sure that annotation processing is enabled on the Maven project.

The other very important thing you do need to know is that Apache Isis leverages DataNucleus for its ORM, and this uses bytecode enhancement rather than runtime proxies (it being an implementation of the JDO API as well as JPA). The DataNucleus bytecode enhancer runs after the compiler but (of course) before the app runs.

  • When using the Maven command line, the datanucleus-maven-plugin is bound to the postCompile phase. So, a simple "mvn package jetty:run" suffices to build the code, run the enhancer and to run the actual app.

  • When compiling with IntelliJ, there’s nothing specific we need to configure to ensure that domain entity clases are enhanced. Because IntelliJ "watches" the filesystem for external changes, we can simply leverage Maven to perform the enhancement just prior to running the app. More on this in the next section.

  • When building in Eclipse, it is necessary to hook into the compile phase to ensure that the enhancement occurs; this is done by installing an Eclipse plugin which runs the datanucleus enhancer.

    This is necessary because Eclipse — unlike IntelliJ — isn’t designed to continually watch the filesystem; any changes to the class files must be made through its "internal" processes.

    Nevertheless, datanucleus’s Eclipse plugin generally works as well as the Maven plugin.

For more info, see the Apache Isis developers' guide for more detailed instructions when using IntelliJ or Eclipse.

Running the app

When running from the IDE, it’s easiest to run using framework-provided bootstrap class, namely org.apache.isis.WebServer. This is just a regular application class (with a main(…​) method) that uses Jetty to run the app (similar to the way in which Spring Boot works, for example).

If using IntelliJ, we’ve found it easiest to set up a run configuration with the "Before launch, run Maven goal" property set up to run the datanucleus enhancer:

intellij run configuration

with

intellij run configuration before launch datanucleus enhance

The command being run here (in the appropriate directory) is simply:

mvn datanucleus:enhance -o

Alternatively the app can be deployed to an app server such as Tomcat (8.x); all the usual files in src/main/webapp are there.

Naked Objects pattern

Apache Isis is an implementation of the naked objects pattern. This means that there’s a direct mapping from the domain object model into the UI. We can explore this by looking at the domain entity and domain service generated by the archetype.

An ORM such as DataNucleus or Hibernate maps domain objects into an RDBMS or other datastore. You can think of Apache Isis (and naked objects) similarly, but it’s an OIM - an object interface mapper. It maps to the UI layer rather than the persistence layer.

Common to both ORMs and OIMs is an internal metamodel; this is where much of the power comes from.

Navigate to HelloWorldObjects; this is a singleton domain service automatically instantiated by the framework. It corresponds to the "Hello World Objects" menu.

The menu items correspond to the actions of this class:

HelloWorldObjects

The actions of that service are used to create and persist instances of HelloWorldObject. The structure and behaviour of this domain entity are similarly reflected:

HelloWorldObject

It’s common for each entity (or more precisely, aggregate root) to have a corresponding domain service, acting as its repository. This abstraction hides the details of interacting with the persistence data store. Domain services are automatically injected wherever they are required, using @javax.inject.Inject.

Apache Isis applications therefore generally follow the hexagonal architecture (aka the ports and adapters architecture).

As well as writing our own domain services, there are also many framework-provided domain services, including RepositoryService (to persist objects) and IsisJdoSupport (for type-safe queries against the database). But this is just the tip of the iceberg; see Apache Isis documentation (specifically: Reference Guide: Domain Services) for the full list.

If there is more than one implementation available, declare a List<SomeDomainService> and all of the available services will be injected. They are sorted by @DomainService#menuOrder attribute.

It’s also possible to override/decorate any of the framework-provided services; just implement the same type with a lower @DomainService#menuOrder.

Domain services also act as extension points for the framework. For example, custom auditing and event publishing can be provided by providing an implementation of the appropriate SPI interface.

UI Hints

The framework derives as much of the UI as possible from the domain objects' intrinsic structure and behaviour, but there are some supporting structures and conventions that are there primarily to improve the UI.

Titles

A title is the identifier of a domain object for the end-user.

For HelloWorldObject, this is defined declaratively:

@Title(prepend = "Object: ")
private String name;

It can also be specified imperatively using either the title() or toString() method.

Mini-Exercise:

(No solution is provided for this exercise).

  • replace the @Title annotation with a title() method:

    public String title() {
        return "Object: " + getName();
    }

Object layout

Frameworks that implement the naked objects pattern automatically provide a default representation of domain objects. In many cases the details of that representation can be inferred directly from the domain members. For example the label of a field for an object’s property (eg HelloWorldObject#name) can be derived directly from the name of the object property itself (getName()).

In the absence of other metadata, Apache Isis will render a domain object with the properties to the left-hand side and the collections (if any) to the right. The order of these properties can be specified using the @MemberOrder annotation, and there are other annotations to group properties together and to associate action buttons with either properties or collections.

The downside of using annotations is that changing the layout requires that the application be restarted, and certain more complex UIs, such as multi-columns or tab groups are difficult or impossible to express.

Therefore Apache Isis also allows the layout of domain objects to be specified using a complementary layout file, eg HelloWorldObject.layout.xml. This is modelled upon bootstrap and so supports arbitrary rows and columns as well as tab groups and tabs.

Mini-Exercise:

  • locate the HelloWorldObject.layout.xml file

  • compare the structure of the layout file to that of the rendered object

  • change the file, eg the relative widths of the columns

  • use the IDE to copy over the file to the classpath; the new version will be picked up automatically

    • for example, with IntelliJ use Run > Reload Changed Classes

To learn more, see the Wicket viewer guide (file-based layout).

Icons

Each domain object is associated with an icon. Typically this is static and in the same package as the class; see HelloWorldObject.png.

menubars.layout.xml

In a similar fashion, the actions of the various domain services are grouped into menus using the menubars.layout.xml file.

Mini-Exercise:

  • locate the menubars.layout.xml file

  • compare the structure of the layout file to that of the rendered menu bar

  • change the file, eg reorder menu items or create new menus

  • again, use the IDE to copy over the file to the classpath

    • for example, with IntelliJ use Run > Reload Changed Classes

To learn more, see the Wicket viewer guide (menu bars layout).