Development Guide

WheatFieldWithCrows

Quickstart

  1. Build Isis with kroviz

    cd ~/isis
    mvn -T 1C clean install \
     -Dmodule-kroviz \
     -Dmaven.source.skip=true
  2. Start kroviz

    cd ~/isis/incubator/clients/kroviz/
    #gradle build
    ./gradlew.sh -t run
  3. Start the Server App

  4. Enter in the Browser:

    http://localhost:3000
  5. Select 'Connect' in the Burger Menu

Originally Apache Isis SimpleApp 1.16.0 was used as the reference RO backend. This required some extra steps in order to deal with CORS setup, see sections on pre 2.0.0-M3 and CORS. Currently (2.0.0-M6) Demo is used as reference - at the moment it’s the only CORS enabled application. === Frontend

Requirements

Kotlin/JS uses Gradle for the build, for the JS runtime NodeJS, and for the JS dependency management part npm. You should have installed: * node js (https://nodejs.org/en/download/current/) * Apache Gradle * Google Chrome (72.0.3626.81 or higher) * <Moesif CORS Plugin (for Chrome)

Build

gradle can be run under Windows with git-bash:

  • ./gradlew.bat tasks # list all gradle tasks

  • ./gradlew.bat webpack-bundle # create main.bundle.js

  • ./gradlew.bat test –exclude-task npm-install

Internally gradle uses npm for the JS part.

In IntelliJ import the gradle project residing in ~/isis/incubator/clients/kroviz/. TIP: In case the project isn’t working as expected, you may try File → Invalidate Caches …​ Alternatively you can e.g. in IntelliJ a Run/Debug Configuration:

Preview
 npm --verbose

If task npm-install hangs, try

 ./gradlew.bat npm-install --info --debug --stacktrace

Helps in identifying thing that may go wrong (e.g. due to proxy settings).

Run

gradlew.bat -t run

Backend

Via Docker Image

Design

In the following section you’ll find information that likely helps understanding the implementation.

Overview

Overview Diagram
Figure 1. Overview Diagram

Patterns Applied

Redux

The implementation is an (independent) reinvention of Redux. I prefer the name Aggregator over Reducer though - IIRC Aggregator is prior art.

Half Object Protocol

The HOP pattern dates back to the early 2000, namely CanooULC. IMO Naked Objects together with the RO API and kroViz resembles something similar.

Transfer Object (JEE / EAA)

TO’s are created from JSON responses

Event Sourcing (EAA)

Requests, reponses, and resulting TO’s are logged. Before requests are sent out to the server this log is consulted and used as a cache.

Proxy (GOF)

The event source acts as a Proxy and thereby saves time and bandwidth.

Aggregator (EAI)

Various aggregators are responsible to collect or assemble displayable objects. Once all layout information is there, the UI will be rendered, even if not all elements of a list have arrived. Those elements will be added as they arrive. This is done with the help of mutable lists.

CollectionAggregator Sequence Diagram
Figure 2. CollectionAggregator Sequence Diagram

Chain of Responsibility (GOF)

A chain of handlers is used to identify what kind of TO is to be generated from the JSON response. Handlers are responsible for initial assignment of aggregators.

Overview Handler
Figure 3. Overview Handler

Template Method (GOF)

The Handler base class makes use of this pattern. Some methods have to be implemented in each subclass, in some cases the default implementation in the base class is used.

Composite Pattern (GOF)

UI elements are hierarchically grouped, cf. *layout.xml

Factory (GOF)

Used for building tables dynamically.

Remote Facade

The Restful Objects API.

Code

Thanks to Kotlin, code is very compact and readable. And, since Kotlin is a typed language and IDE’s can infer a lot about the code, there are only few surprises. Nevertheless Kotlin/JS allows to use JavaScript features alongside the typed part, what effectively makes it a dynamic language.

Hot Spots

Look out for places where typing is escaped and the DOM is manipulated directly:

  • asDynamic()

  • hasOwnProperty()

  • stopPropagation()

  • getElementById()

Trouble Shooting

Corporate Firewall with SSL 'inspection'

There are some questionable setups in coporate settings that are based on SSL replacement. In order to cope with it, you may try to import the Certificate into cacerts, see https://intellij-support.jetbrains.com/hc/en-us/community/posts/115000094584-IDEA-Ultimate-2016-3-4-throwing-unable-to-find-valid-certification-path-to-requested-target-when-trying-to-refresh-gradle

Network Proxy

 Depending on the network you are in, you may need to configure the proxy settings. Among the relevant files are:
 `bash
    ~/.npmrc
    ~/.gitconfig
    ~/.ssh/config
    ~/.ssh/id_rsa
`
 ### References
 * https://jjasonclark.com/how-to-setup-node-behind-web-proxy/
 * https://gist.github.com/EudesSilva/0329645b9c258e0495544b8a5ccd1454

Access to git from npm

Problem

   npm ERR! Error while executing:
   npm ERR! C:\Program Files\Git\bin\git.EXE ls-remote -h -t ssh://git@github.com/jarecsni/font-awesome-webpack.git
   npm ERR!
   npm ERR! git@ssh.github.com: Permission denied (publickey).
   npm ERR! fatal: Could not read from remote repository.
   npm ERR!
   npm ERR! Please make sure you have the correct access rights
   npm ERR! and the repository exists.
   npm ERR!
   npm ERR! exited with error code: 128

Solution

~/.ssh/config
ProxyCommand /bin/connect.exe -H proxy.server.name:3128 %h %p
Host github.com
 User git
 Port 22
 Hostname github.com
 IdentityFile "C:\users\username.ssh\id_rsa"
 TCPKeepAlive yes
 IdentitiesOnly yes
Host ssh.github.com
 User git
 Port 443
 Hostname ssh.github.com
 IdentityFile "C:\users\username.ssh\id_rsa"
 TCPKeepAlive yes
 IdentitiesOnly yes

Karma-Tests do not respond to code changes

Windows:

taskkill /f /im node.exe

Linux:

killall node

Misc

Toolchain Overview

When you are accustomed to the well settled Java ecosystem with integrated development environments, prepare yourself for learning new tools and addressing new problems.

Kotlin is straightforward and once you know it, you may not want to go back.

Development MindMap
Figure 4. Development MindMap

The Browser as Client Runtime Environment

Google Chrome is used as browser. It has a very feature rich debugger (<CTRL>-<SHIFT>-I) which can even be connected to IntelliJ’s debugger (Settings → Preferences → Extension → Link handling). For a nice introduction to Chrome, see: https://www.google.com/googlebooks/chrome/.

All current browsers implement some security features in order to counteract Cross-Site-Resource-Forgery (XSRF). CORS (Cross-Origin-Resource-Sharing) is beeing devised to allow access to resources from a different host-port under certain circumstances. It is said to be bypassable via https://www.npmjs.com/package/node-iframe, cf. https://stackoverflow.com/questions/33143776/ajax-request-refused-to-set-unsafe-header/66782595#66782595

Visualize JS dependencies

Measure Test Coverage

nyc npm test

Gradle Build Overview

Development Overview Diagram
Figure 5. Development Overview Diagram

Build the Backend Yourself

Tool Chain

  • (Oracle) JDK 11 (or higher)

  • Apache Maven 3.6.3 (or later)

Create from Archetype

Create from the Apache Isis SimpleApp archetype:

mvn archetype:generate \
    -D archetypeGroupId=org.apache.isis.archetype \
    -D archetypeArtifactId=simpleapp-archetype \
    -D archetypeVersion=2.0.0-M3 \
    -D groupId=org.my \
    -D artifactId=myapp-2.0.0-M3 \
    -D version=1.0.0 -B

Compile

mvn clean install -DskipTests

Run

cd webapp
mvn -Djetty.port=8080 jetty:run -DPROTOTYPING

Appendix

JSON Terminology

See: elp.kapowsoftware.com/9.4/index.jsp?topic=/doc/rm/JSONTerminology.html

JSON Text

JSON Object | JSON Array

JSON Object

{} | { Properties }

JSON Array

[] | [ Items ]

Properties

Property, Properties

Property

String : JSON Value

Items

JSON Value, Items

JSON Value

JSON Text | String | Number | false | null | true

String

"" | " Characters "

Characters

Character Characters

Character

any Unicode character except ", \ or control character | " | \ | \/ | \b | \f | \n | \r | \t | \u 4 hex digits

Number

a number very much like a C or Java number, see RFC 4627 for details.

CORS

CORS stands for 'Cross Origin Resource Sharing' aka: 'Same Origin Policy' was designed to improve security and is implemented in browsers. In short it means: your browser will allow loading of resources only if host and port are identical to the url you are on. Ie. webpage loaded from http://localhost:8088/ resources from http://localhost:8080/restful will not be accessible.

Solution 2:

Add to webapp\src\main\webapp\WEB-INF\web.xml
<!-- CORS filter for XmlHttpRequests -->
<filter>
    <filter-name>cross-origin</filter-name>
    <filter-class>org.eclipse.jetty.servlets.CrossOriginFilter</filter-class>
    <init-param>
        <param-name>allowedOrigins</param-name>
        <param-value>*</param-value>
    </init-param>
    <init-param>
        <param-name>allowedMethods</param-name>
        <value>*</value>
    </init-param>
    <init-param>
        <param-name>allowedHeaders</param-name>
        <param-value>*</param-value>
    </init-param>
    <init-param>
        <param-name>supportsCredentials</param-name>
        <param-value>true</param-value>
    </init-param>
    <init-param>
        <param-name>chainPreflight</param-name>
        <param-value>false</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>cross-origin</filter-name>
    <url-pattern>/restful/*</url-pattern>
</filter-mapping>

`

Solution 3:

Incorporate kroviz.js e.g. in the WAR containing your Apache Isis backend.

Extensions

OSM/Leaflet

Chart.js

  • SanKey diagarms, see CodePen example