HelloWorld

The quickest way to start learning about Apache Isis is to use the helloworld starter app.

This will download a tiny Apache Isis app, consisting of a simple one-class domain model, namely the HelloWorldObject entity and a supporting HelloWorldObjects repository domain service. Both the business logic and supporting bootstrapping classes are in a single Maven module (in different Java packages).

We don’t recommend that you use the helloworld starter app as the basis for your own applications. Instead, use the SimpleApp starter app. It also creates a minimal application, but provides more structure and example tests, useful as you build out your own app.

Prerequisites

Apache Isis is a Java based framework, so in terms of prerequisites, you’ll need to install:

  • an LTS version of Java: either Java 8 JDK or Java 11 JDK

  • Apache Maven 3.5+

You’ll probably also want to use an IDE; the Apache Isis committers use either IntelliJ or Eclipse; in the Setup Guide we have detailed setup instructions for using these two IDEs. If you’re a NetBeans user you should have no problems as it too has strong support for Maven.

When building and running within an IDE, you’ll also need to configure the Datanucleus enhancer. This is implemented as a Maven plugin, so in the case of IntelliJ, it’s easy enough to run the enhancer as required. It should be just as straightforward for NetBeans too.

For Eclipse the maven integration story is a little less refined. All is not lost, however; DataNucleus also has an implementation of the enhancer as an Eclipse plugin, which works well enough.

Downloading & Running

Create a new directory, and cd into that directory.

To build the app from the latest stable release, then run the following command:

curl https://codeload.github.com/apache/isis-app-helloworld/zip/2.0.0-M3 | jar xv
cd isis-app-helloworld-2.0.0-M3

mvn clean install
mvn spring-boot:run

This should only take a few seconds to download, compile and run. Then browse to http://localhost:8080, and read on.

Using the App

When you start the app, you’ll be presented with a welcome page from which you can access the webapp using either the generic UI provided by Wicket viewer or use Swagger to access the Restful Objects viewer:

010 root page

Choose the generic Wicket UI, and navigate to the login page:

020 login to wicket viewer

The app itself is configured to run using shiro security, as configured in the WEB-INF/shiro.ini config file. You can login with:

  • username: sven

  • password: pass

Wicket viewer

Once you’ve logged in you’ll see the default home page:

030 home page

Create an object

The application is configured to run with an in-memory database, so initially there is no data. Create an object using the menu:

040 create object from menu

which brings up a modal dialog:

050 create object from menu prompt

hitting OK returns the created object:

060 created object

The above functionality is implemented by this code:

@Action(semantics = SemanticsOf.NON_IDEMPOTENT)
@ActionLayout(promptStyle = PromptStyle.DIALOG_MODAL)
public HelloWorldObject create(
        @Name final String name) {
    return repositoryService.persist(new HelloWorldObject(name));
}
public String default0Create() {
    return "Hello World!";
}

Invoke an action

The HelloWorldObject contains a couple of properties, and a single action to update that property.

The name property is read-only, and can only be modified using the updateName action:

070 update name

The above functionality is implemented by this code:

@Action(semantics = SemanticsOf.IDEMPOTENT,
        publishing = Publishing.ENABLED,        (1)
        associateWith = "name")
public HelloWorldObject updateName(
        @Name final String name) {
    setName(name);
    return this;
}
public String default0UpdateName() {
    return getName();
}
1 Publishing enabled means that the action invocation is converted into XML and dispatched to all configured implementations of the PublisherService SPI.

The framework provides a default implementation that just logs the interaction:

075 logged action

Edit a property

The notes property is editable, and can be edited in-place. For example:

080 edit notes

Actions requiring confirmations

It’s also possible to delete an object:

090 delete object

The viewer displays a message confirming that the object has been deleted:

100 object deleted

The above functionality is implemented by this code:

@Action(semantics = SemanticsOf.NON_IDEMPOTENT_ARE_YOU_SURE)
@ActionLayout(position = ActionLayout.Position.PANEL)
public void delete() {
    final String title = titleService.titleOf(this);                    (1)
    messageService.informUser(String.format("'%s' deleted", title));
    repositoryService.removeAndFlush(this);
}
1 Note that this method uses three services provided by the framework; these are injected into the domain object automatically.

Swagger (Restful Objects)

Using Prototyping  Open Swagger UI menu item (or just going back to the home page at localhost:8080) we can use Swagger UI as a front-end to the REST API provided by the Restful Objects viewer.

200 swagger ui before reload

The public API (where the calling client is assumed to be 3rd party) only exposes view models, not entities. If the API is private (or for prototyping), then resources corresponding to entities are also exposed:

210 helloworld resources

For example, an object can be created using the resource that represents the HelloWorldObjects#create action:

220 create object thru rest api
if invoking the action returns a 401 (unauthorised), then navigate to the REST API directly (http://localhost:8080/restful to authenticate the browser first]).

The response indicates that the object was successfully created:

230 create object thru rest api response

The Swagger UI also provides a resource to retrieve any object:

240 retrieve object using rest api

This results in a representation of the domain object (as per the requested Response Content Type, ie ACCEPT header):

250 retrieve object using rest api response

The Swagger UI is provided as a convenience; the REST API is actually a complete hypermedia API (in other words you can follow the links to access all the behaviour exposed in the regular Wicket app). The REST API implemented by Apache Isis is specified in the Restful Object spec.

Structure of the App

The helloworld starter app consists of a single Maven module.

src/main/java

Under src/main/java we have:

src/main/java/
  domainapp/                            (1)
    modules
      hello/                            (2)
        dom/                            (3)
          hwo/                          (4)
            HelloWorldObject.java
            HelloWorldObject.layout.xml
            HelloWorldObject.png
            HelloWorldObjects.java
        types/                          (5)
          Name.java
          Notes.java
      HelloWorldModule.java             (6)
    webapp/
      AppManifest.java                  (7)
      HelloWorldApp.java                (8)
  META-INF/
    persistence.xml                     (9)
1 For simplicity, all the Java source files reside in a domainapp top-level package. Change as required.
2 Defines the 'hello' module. Apache Isis can be used for both microservice and monolithic architectures, but for the latter it encourages "modular monoliths" from the start.
3 The dom package holds the "domain object model" for this module. Modules may have other packages, common ones include types (as below), also apis, contributions, fixtures, spis
4 Holds classes for the hwo ("hello world object") entity/aggregate, consisting of the entity definition itself (HelloWorldObject) and a corresponding repository (HelloWorldObjects). The associated .layout.xml and .png are optional but provide metadata/resources for rendering (Maven is configured to also treat src/main/java as a resource location).
5 The types package contains meta-annotations to describe the usage of common value types such as Strings.
6 HelloWorldModule is a Spring @Configuration which allows the domain services and entities of the module to be located.
This is discussed in more detail below.
7 AppManifest is the top-level Spring @Configuration that specifies the components of Apache Isis to use, along with the modules making up the application itself (ie HelloWorldModule).
This is discussed in more detail below.
8 HelloWorldApp is the @SpringBootApplication used to bootstrap the app. It’s pretty much boilerplate - the important piece is that it references AppManifest.
This is discussed in more detail below.
9 The persistence.xml file is required when using the JDO/DataNucleus object store (though it is basically boilerplate, an empty file).

HelloWorldModule

Every module within an Apache Isis application should have a module class. Its purpose is to define a package to scan from, and optionally to declare any transitive dependencies. In the case of HelloWorldModule, it is extremely simple:

HelloWorldModule.java
package domainapp.modules.hello;
... imports omitted ...
@Configuration
@Import({})                         (1)
@ComponentScan                      (2)
public class HelloWorldModule {
}
1 no dependencies. If there were, these would be expressed in terms of module classes (each being a Spring @Configuration)
2 specifies this class' package as a root to scan for Spring @Components.

The scanning mechanism is leveraged by Apache Isis to pick up three types of classes:

This will pick up the HelloWorldObjects repository because it is annotated with the framework’s @DomainService annotation (in turn meta-annotated with @Component).

  • all domain services

    These are classes that are annotated with the framework’s @DomainService annotation. Because @DomainService is meta-annotated as a @Component, these are found automatically and are managed by Spring.

    Depending on their nature, domain services are used to build up the menu, or are available to call programmatically, eg repositories, or sometimes both.

    In the helloworld starter app, the only domain service is HelloWorldObjects. This appears in the menu, and also acts as a repository for the HelloWorldObject entity.

  • all entities.

    These are entities that are annotated with both @DomainObject annotation and with @javax.jdo.annotations.PersistenceCapable. Because @DomainObject is meta-annotated as a @Component, these are found automatically by Spring. They are passed through to the JDO/DataNucleus object store, in order to create database mappings from the entities to relational tables. It is also annotated with @DomainObject

    In the helloworld starter app, the only entity is HelloWorldObject.

  • all fixture scripts

    These are classes that extend from the testing applib’s FixtureScript class, and are used to setup the database when running in prototype mode (against an in-memory database).

    The helloworld starter app doesn’t provide any examples of these.

AppManifest

The "app manifest" (the name has been retained from Apache Isis v1.x) is the top-level Spring @Configuration. In the case of the helloworld starter app, the AppManifest looks like this:

AppManifest.java
@Configuration
@Import({
        IsisModuleCoreRuntimeServices.class,                    (1)
        IsisModuleSecurityShiro.class,                          (2)
        IsisModuleJdoDataNucleus5.class,                        (3)
        IsisModuleViewerRestfulObjectsJaxrsResteasy4.class,     (4)
        IsisModuleViewerWicketViewer.class,                     (5)

        IsisModuleTestingH2ConsoleUi.class,                     (6)

        HelloWorldModule.class                                  (7)
})
@PropertySource(IsisPresets.NoTranslations)                     (8)
public class AppManifest {
}
1 Mandatory - specifies the core of the Apache Isis framework
2 Enables the Shiro security mechanism. There are several security implementations, precisely one must be selected
3 Enables JDO/DataNucleus for persistence. Optional (though if omitted then only view models may be used, with hand-rolled persistence).
4 Enables the Restful Objects viewer (ie REST API).
5 Enables the Wicket viewer
6 Enables the H2 Console (menu from the "Prototyping" menu), applicable only if running against h2 in-memory database.
7 References the application’s module(s), in this case just the one, HelloWorldModule.
8 Normally configuration properties are picked up from Spring Boot’s application.properties or application.yml files, but additional properties can be overridden directly. This particular one disables the framework’s i18n support using the IsisPresets convenience class.

HelloWorldApp

The application is bootstrapped using HelloWorldApp, a regular @SpringBootApplication. It is mostly boilerplate:

@SpringBootApplication
@Import({
    AppManifest.class,                                          (1)
})
public class HelloWorldApp
            extends SpringBootServletInitializer {

    public static void main(String[] args) {
        IsisPresets.prototyping();                              (2)
        SpringApplication.run(
                new Class[] { HelloWorldApp.class }, args);
    }
}
1 references the AppManifest mentioned earlier
2 specifies prototyping mode. This enables actions marked for prototyping to become available, useful during the early stages of development.

As an alternative to making this call, you can also just run with a system property:

-DPROTOTYPING=true

src/main/resources

Under src/main/resources we have:

src/main/resources
  config/
    application.properties      (1)
  static/                       (2)
  templates/                    (3)
  application.yml               (4)
  banner.txt                    (5)
  log4j2-spring.xml             (6)
  menubars.layout.xml           (7)
  shiro.ini                     (8)
1 By convention, we use config/application.properties to hold configuration properties that change between environments (dev, test, prod). Typically this just holds JDBC connection strings, etc.
2 The static package (a Spring convention) provides access for static resources that are accessible from the webapp
3 The templates package holds a fallback error page, which is the default location for pages rendered using Spring Boot’s integration with Thymeleaf.
4 By convention, we use application.yml to hold configuration properties that do not change between environments.
5 The banner.txt is shown when bootstrapping.
6 The log4j2-spring.xml configures log4j2 (the logging system used by Apache Isis)
7 The menubars.layout.xml arranges the actions of the domain services into menus.
8 The shiro.ini file configures Shiro security integration (see the IsisModuleSecurityShiro module imported in the AppManifest, above).

The Shiro security integration is much more flexible than simple file-based authentication.

To call out some of the files under static:

  • The index.html is the page shown at the root of the package, providing links to either the Wicket viewer or to the Swagger UI. In a production application this is usually replaced with a page that does an HTTP 302 redirect to the Wicket viewer.

  • In css/application.css you can use to customise CSS, typically to highlight certain fields or states. The pages generated by the Wicket viewer have plenty of CSS classes to target. You can also implement the cssClass() method in each domain object to provide additional CSS classes to target.

  • Similarly, in scripts/application.js you have the option to add arbitrary Javascript. JQuery is available by default.

No src/main/webapp

Note that there is no src/main/webapp/ or WEB-INF/web.xml - the servlets and filters are configured by Apache Isis automatically.

src/test/java

Under src/test/java we have:

src/test/java/
  domainapp/
    modules/
      hello/
        dom/
          hwo/                          (1)
            HelloWorldObject_Test.java
            HelloWorldObjects_Test.java
1 These are very simple unit tests of HelloWorldObject and HelloWorldObjects, with the package structure the same as in src/main/java. They are written in JUnit 5 and use Mockito as the mocking library.

pom.xml

Finally, at the root directory we of course have the pom.xml. This inherits from isis-app-starter-parent:

pom.xml
<parent>
  <groupId>org.apache.isis.app</groupId>
  <artifactId>isis-app-starter-parent</artifactId>
  <version>XXX</version>
</parent>

... which builds upon Spring Boot’s own org.springframework.boot:spring-boot-starter-parent. This means:

  • the set of third party dependencies declared have been validated as compatible by Spring Boot team

  • build plugins are declared and configured appropriately

  • imports to the Apache Isis dependencies are declared via <dependencyManagement>

Running from within the IDE

Most of the time you’ll probably want to run the app from within your IDE. The mechanics of doing this will vary by IDE; see the Setup Guide for details of setting up Eclipse or IntelliJ IDEA. Basically, though, it amounts to running the main() method in the HelloWorldApp, but also (and this bit is important) ensuring that the DataNucleus enhancer has properly processed all domain entities.

Here’s what the setup looks like in IntelliJ IDEA:

helloworld

which uses an IntelliJ feature to execute a different Run Configuration for the DataNucleus enhancer beforehand:

helloworld before launch

Experimenting with the App

Once you are familiar with the app, try modifying it. There is plenty more guidance on this site; start with the User Guide Fundamentals and then look at the other guides linked to from the top-level menu or from the main table of contents.

If you run into issues, please don’t hesitate to ask for help on the users mailing list or the Slack channel, as per the support page.

Moving on

When you are ready to start working on your own app, we don’t recommend building on top of the helloworld app.

Instead, we suggest that you start with the simpleapp starter app. Although a little more complex, it provides more structure and example tests, all of which will help guide you as your application grows.